



<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#FFF">
  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon.png">

<link rel="icon" type="image/ico" sizes="32x32" href="/blog/images/favicon.ico">
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv="Cache-Control" content="no-siteapp">


<link rel="alternate" type="application/rss+xml" title="Endless" href="http://fairy77.gitee.io/rss.xml" />
<link rel="alternate" type="application/atom+xml" title="Endless" href="http://fairy77.gitee.io/atom.xml" />
<link rel="alternate" type="application/json" title="Endless" href="http://fairy77.gitee.io/feed.json" />

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Mulish:300,300italic,400,400italic,700,700italic%7CFredericka%20the%20Great:300,300italic,400,400italic,700,700italic%7CNoto%20Serif%20JP:300,300italic,400,400italic,700,700italic%7CNoto%20Serif%20SC:300,300italic,400,400italic,700,700italic%7CInconsolata:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext">

<link rel="stylesheet" href="/blog/css/app.css?v=0.2.5">

  
  <meta name="keywords" content="SpringBoot" />


<link rel="canonical" href="http://fairy77.gitee.io/2020/03/08/SpringBoot/">



  <title>
SpringBoot 学习笔记 1 |
夏季大三角 = Endless</title>
<meta name="generator" content="Hexo 5.4.0"></head>
<body itemscope itemtype="http://schema.org/WebPage">
  <div id="loading">
    <div class="cat">
      <div class="body"></div>
      <div class="head">
        <div class="face"></div>
      </div>
      <div class="foot">
        <div class="tummy-end"></div>
        <div class="bottom"></div>
        <div class="legs left"></div>
        <div class="legs right"></div>
      </div>
      <div class="paw">
        <div class="hands left"></div>
        <div class="hands right"></div>
      </div>
    </div>
  </div>
  <div id="container">
    <header id="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="inner">
        <div id="brand">
          <div class="pjax">
          
  <h1 itemprop="name headline">SpringBoot 学习笔记 1
  </h1>
  
<div class="meta">
  <span class="item" title="创建时间：2020-03-08 14:36:37">
    <span class="icon">
      <i class="ic i-calendar"></i>
    </span>
    <span class="text">发表于</span>
    <time itemprop="dateCreated datePublished" datetime="2020-03-08T14:36:37+08:00">2020-03-08</time>
  </span>
  <span class="item" title="本文字数">
    <span class="icon">
      <i class="ic i-pen"></i>
    </span>
    <span class="text">本文字数</span>
    <span>87k</span>
    <span class="text">字</span>
  </span>
  <span class="item" title="阅读时长">
    <span class="icon">
      <i class="ic i-clock"></i>
    </span>
    <span class="text">阅读时长</span>
    <span>1:19</span>
  </span>
</div>


          </div>
        </div>
        <nav id="nav">
  <div class="inner">
    <div class="toggle">
      <div class="lines" aria-label="切换导航栏">
        <span class="line"></span>
        <span class="line"></span>
        <span class="line"></span>
      </div>
    </div>
    <ul class="menu">
      <li class="item title"><a href="/blog/" rel="start">夏季大三角</a></li>
    </ul>
    <ul class="right">
      <li class="item theme">
        <i class="ic i-sun"></i>
      </li>
      <li class="item search">
        <i class="ic i-search"></i>
      </li>
    </ul>
  </div>
</nav>

      </div>
      <div id="imgs" class="pjax">
        <ul>
          <li class="item" data-background-image="https://tva1.sinaimg.cn/large/6833939bly1gipexw3o58j20zk0m8e81.jpg"></li>
          <li class="item" data-background-image="https://tva1.sinaimg.cn/large/6833939bly1gipetfk5zwj20zk0m8e81.jpg"></li>
          <li class="item" data-background-image="https://tva1.sinaimg.cn/large/6833939bly1gicliwyw55j20zk0m8hdt.jpg"></li>
          <li class="item" data-background-image="https://tva1.sinaimg.cn/large/6833939bly1gicivghyooj20zk0m8dir.jpg"></li>
          <li class="item" data-background-image="https://tva1.sinaimg.cn/large/6833939bly1gicitzannuj20zk0m8b29.jpg"></li>
          <li class="item" data-background-image="https://tva1.sinaimg.cn/large/6833939bly1giclimtf7dj20zk0m8qav.jpg"></li>
        </ul>
      </div>
    </header>
    <div id="waves">
      <svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto">
        <defs>
          <path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
        </defs>
        <g class="parallax">
          <use xlink:href="#gentle-wave" x="48" y="0" />
          <use xlink:href="#gentle-wave" x="48" y="3" />
          <use xlink:href="#gentle-wave" x="48" y="5" />
          <use xlink:href="#gentle-wave" x="48" y="7" />
        </g>
      </svg>
    </div>
    <main>
      <div class="inner">
        <div id="main" class="pjax">
          
  <div class="article wrap">
    
<div class="breadcrumb" itemscope itemtype="https://schema.org/BreadcrumbList">
<i class="ic i-home"></i>
<span><a href="/blog/">首页</a></span>
</div>

    <article itemscope itemtype="http://schema.org/Article" class="post block" lang="zh-CN">
  <link itemprop="mainEntityOfPage" href="http://fairy77.gitee.io/2020/03/08/SpringBoot/">

  <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="image" content="/blog/images/avatar.jpg">
    <meta itemprop="name" content="Rain Bear">
    <meta itemprop="description" content=", ">
  </span>

  <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="Endless">
  </span>

  <div class="body md" itemprop="articleBody">
    

    <p><span class="exturl" data-url="aHR0cHM6Ly93d3cuYmlsaWJpbGkuY29tL3ZpZGVvL2F2MjA5NjUyOTU=">参考视频</span></p>
<h1 id="一-spring-boot入门"><a class="markdownIt-Anchor" href="#一-spring-boot入门">#</a> 一、Spring Boot 入门</h1>
<h2 id="1-spring-boot简介"><a class="markdownIt-Anchor" href="#1-spring-boot简介">#</a> 1. Spring Boot 简介</h2>
<blockquote>
<p>简化 Spring 应用开发的一个框架；</p>
<p>整个 Spring 技术栈的一个大整合；</p>
<p>J2EE 开发的一站式解决方案；</p>
</blockquote>
<span id="more"></span>
<h2 id="2-微服务"><a class="markdownIt-Anchor" href="#2-微服务">#</a> 2. 微服务</h2>
<p>2014，Martin Fowler</p>
<p>微服务：架构风格</p>
<p>一个应用应该是一族小型服务；可以通过 HTTP 的方式进行互通；</p>
<p>单体应用：ALL IN ONE</p>
<p>微服务：每一个功能元素最终都是一个可独立替换和独立升级的软件单元；</p>
<p>详细参照<span class="exturl" data-url="aHR0cHM6Ly9tYXJ0aW5mb3dsZXIuY29tL2FydGljbGVzL21pY3Jvc2VydmljZXMuaHRtbA==">微服务文档</span></p>
<p>环境约束</p>
<p>-jdk1.8</p>
<p>-maven3.x</p>
<p>-Intellij IDEA</p>
<p>-SpringBoot</p>
<h2 id="3-环境准备"><a class="markdownIt-Anchor" href="#3-环境准备">#</a> 3. 环境准备</h2>
<h3 id="31-maven设置"><a class="markdownIt-Anchor" href="#31-maven设置">#</a> 3.1 MAVEN 设置</h3>
<p>给 maven 的 settings.xml 配置文件的 profiles 标签添加</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;profile&gt;</span><br><span class="line">    &lt;id&gt;jdk-<span class="number">1.8</span>&lt;/id&gt;</span><br><span class="line">    &lt;activation&gt;</span><br><span class="line">        &lt;activeByDefault&gt;<span class="keyword">true</span>&lt;/activeByDefault&gt;</span><br><span class="line">        &lt;jdk&gt;<span class="number">1.8</span>&lt;/jdk&gt;</span><br><span class="line">    &lt;/activation&gt;</span><br><span class="line">    &lt;properties&gt;</span><br><span class="line">        &lt;maven.compiler.source&gt;<span class="number">1.8</span>&lt;/maven.compiler.source&gt;</span><br><span class="line">        &lt;maven.compiler.target&gt;<span class="number">1.8</span>&lt;/maven.compiler.target&gt;</span><br><span class="line">        &lt;maven.compiler.compilerVersion&gt;<span class="number">1.8</span>&lt;/maven.compiler.compilerVersion&gt;</span><br><span class="line">    &lt;/properties&gt;</span><br><span class="line">&lt;/profile&gt;</span><br></pre></td></tr></table></figure>
<h3 id="32-idea设置"><a class="markdownIt-Anchor" href="#32-idea设置">#</a> 3.2 IDEA 设置</h3>
<p><img data-src="SpringBoot/IDEA%E9%85%8D%E7%BD%AE.jpg" alt=""></p>
<h2 id="4-spring-boot-helloworld"><a class="markdownIt-Anchor" href="#4-spring-boot-helloworld">#</a> 4. Spring Boot HelloWorld</h2>
<p>一个功能</p>
<p>浏览器发送 hello 请求，服务器接收请求处理，响应 HelloWorld 字符串；</p>
<h3 id="41-创建一个maven工程jar"><a class="markdownIt-Anchor" href="#41-创建一个maven工程jar">#</a> 4.1 创建一个 maven 工程；(jar)</h3>
<h3 id="42-导入springboot相关依赖"><a class="markdownIt-Anchor" href="#42-导入springboot相关依赖">#</a> 4.2 导入 springboot 相关依赖</h3>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.2.5.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">relativePath</span>/&gt;</span> <span class="comment">&lt;!-- lookup parent from repository --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="43-编写一个主程序启动spring-boot应用"><a class="markdownIt-Anchor" href="#43-编写一个主程序启动spring-boot应用">#</a> 4.3 编写一个主程序，启动 Spring Boot 应用</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@SpringBootApplication</span> 来标注一个主程序类，说明这是一个Spring Boot应用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloWorldMainApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// Spring应用启动起来</span></span><br><span class="line">        SpringApplication.run(HelloWorldMainApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="44-编写相关的controller-service"><a class="markdownIt-Anchor" href="#44-编写相关的controller-service">#</a> 4.4 编写相关的 controller、service</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;hello world!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="45-运行主程序测试"><a class="markdownIt-Anchor" href="#45-运行主程序测试">#</a> 4.5 运行主程序测试</h3>
<h3 id="46-简化部署"><a class="markdownIt-Anchor" href="#46-简化部署">#</a> 4.6 简化部署</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 这个插件，可以将应用打包成一个可执行的jar包 --&gt;</span><br><span class="line">    &lt;build&gt;</span><br><span class="line">        &lt;plugins&gt;</span><br><span class="line">            &lt;plugin&gt;</span><br><span class="line">                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;</span><br><span class="line">            &lt;/plugin&gt;</span><br><span class="line">        &lt;/plugins&gt;</span><br><span class="line">    &lt;/build&gt;</span><br></pre></td></tr></table></figure>
<p>将这个应用打成 jar 包，直接使用 java -jar 的命令进行执行</p>
<h2 id="5-hello-world探究"><a class="markdownIt-Anchor" href="#5-hello-world探究">#</a> 5. Hello World 探究</h2>
<h3 id="51-pom文件"><a class="markdownIt-Anchor" href="#51-pom文件">#</a> 5.1 POM 文件</h3>
<h4 id="511-父项目"><a class="markdownIt-Anchor" href="#511-父项目">#</a> 5.1.1 父项目</h4>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;parent&gt;</span><br><span class="line">    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;<span class="number">2.2</span><span class="number">.5</span>.RELEASE&lt;/version&gt;</span><br><span class="line">    &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;</span><br><span class="line">&lt;/parent&gt;</span><br><span class="line">他的父项目是：</span><br><span class="line">&lt;parent&gt;</span><br><span class="line">    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;spring-boot-dependencies&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;<span class="number">2.2</span><span class="number">.5</span>.RELEASE&lt;/version&gt;</span><br><span class="line">    &lt;relativePath&gt;../../spring-boot-dependencies&lt;/relativePath&gt;</span><br><span class="line">&lt;/parent&gt;</span><br><span class="line">他来真正管理Spring Boot应用里面的所有依赖版本</span><br></pre></td></tr></table></figure>
<p>Spring Boot 的版本仲裁中心；</p>
<p>以后我们导入依赖默认是不需要写版本的；（没有在 dependencies 里面管理的依赖自然需要声明版本号）</p>
<h4 id="512-启动器"><a class="markdownIt-Anchor" href="#512-启动器">#</a> 5.1.2 启动器</h4>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure>
<p><strong>spring-boot-starter</strong>-<mark>web</mark></p>
<p>​		spring-boot-starter：spring-boot 场景启动器；帮我们导入了 web 模块征程运行所依赖的组件；</p>
<p>Spring Boot 将所有的功能场景都抽取出来，做成一个个 starters（启动器），只需要在项目里引入这些 starter，相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器。</p>
<h3 id="52-主程序类主入口类"><a class="markdownIt-Anchor" href="#52-主程序类主入口类">#</a> 5.2 主程序类，主入口类</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@SpringBootApplication</span> 来标注一个主程序类，说明这是一个Spring Boot应用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloWorldMainApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// Spring应用启动起来</span></span><br><span class="line">        SpringApplication.run(HelloWorldMainApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>@<strong>SpringBootApplication</strong>：Spring Boot 应用标注在某个类上说明这个类是 SpringBoot 的主配置类，SpringBoot</p>
<p>就应该运行这个类的 main 方法来启动 SpringBoot 应用；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Target(&#123;ElementType.TYPE&#125;)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Inherited</span></span><br><span class="line"><span class="meta">@SpringBootConfiguration</span></span><br><span class="line"><span class="meta">@EnableAutoConfiguration</span></span><br><span class="line"><span class="meta">@ComponentScan(</span></span><br><span class="line"><span class="meta">    excludeFilters = &#123;@Filter(</span></span><br><span class="line"><span class="meta">    type = FilterType.CUSTOM,</span></span><br><span class="line"><span class="meta">    classes = &#123;TypeExcludeFilter.class&#125;</span></span><br><span class="line"><span class="meta">), @Filter(</span></span><br><span class="line"><span class="meta">    type = FilterType.CUSTOM,</span></span><br><span class="line"><span class="meta">    classes = &#123;AutoConfigurationExcludeFilter.class&#125;</span></span><br><span class="line"><span class="meta">)&#125;</span></span><br><span class="line"><span class="meta">)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> SpringBootApplication &#123;</span><br></pre></td></tr></table></figure>
<p>@<strong>SpringBootConfiguration</strong>：Spring Boot 的配置类；</p>
<p>​		标注在某个类上，表示这是一个 Spring Boot 的配置类</p>
<p>​		@<strong>Configuration</strong>：配置类上标注这个注解；</p>
<p>​				配置类 ------ 配置文件；配置类也是容器中的一个组件；@Component</p>
<p>@<strong>EnableAutoConfiguration</strong>：开启自动配置功能</p>
<p>​		以前我们需要配置的东西，Spring Boot 帮我们自动配置；@EnableAutoConfiguration 告诉 SpringBoot 开启		自动配置功能；这样自动配置才能生效。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@AutoConfigurationPackage</span></span><br><span class="line"><span class="meta">@Import(&#123;AutoConfigurationImportSelector.class&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> EnableAutoConfiguration &#123;</span><br></pre></td></tr></table></figure>
<p>​		@<strong>AutoConfigurationPackage</strong>：自动配置包</p>
<p>​				@<strong>Import</strong>({Registrar.class})；</p>
<p>​				spring 的底层注解 @import，给容器中导入一个组件；导入的组件由 Registrar.class；</p>
<p>​				<mark>将主配置类（@SpringBootApplication 标注的类）的所在包及下面所有子包里面的所有组件扫描到 spring 容器；</mark></p>
<p>​		@<strong>Import</strong>({AutoConfigurationImportSelector.class})；</p>
<p>​				给容器中导入组件？</p>
<p>​				AutoConfigurationImportSelector.class：导入哪些组件的选择器；</p>
<p>​				将所有需要导入的组件以全类名的方式返回；这些组件就会被添加到容器中；</p>
<p>​				会给容器中导入非常多的自动配置类（xxxAutoConfiguration）；就是给容器中导入这个场景需要的所有组件，并配置好这些组件。</p>
<p>​				<img data-src="SpringBoot/%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB.jpg" alt=""></p>
<p>有了自动配置类，免去了我们手动编写配置注入功能组件等工作；</p>
<p>​				SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader);</p>
<p>​				==SpringBoot 在启动的时候，从类路径下的 META-INF/spring.factories 中获取 EnableAutoConfiguration 指定的值，将这些值作为自动配置类导入到容器中，自动配置类就生效，帮我们进行自动配置工作；== 以前我们需要自己配置的东西，自动帮我们配置了；</p>
<p>​				J2EE 的整体整合解决方案和自动配置都在 spring-boot-autoconfigure-2.2.5.RELEASE.jar 中；</p>
<h2 id="6-使用spring-initializer快速穿建spring-boot项目"><a class="markdownIt-Anchor" href="#6-使用spring-initializer快速穿建spring-boot项目">#</a> 6. 使用 Spring Initializer 快速穿建 Spring Boot 项目</h2>
<p>IDE 都支持使用 Spring 的项目穿建向导快速穿建一个 Spring Boot 项目；</p>
<p>选择我们需要的模块；向导会联网创建 Spring Boot 项目；</p>
<p>默认生成的 Spring Boot 项目；</p>
<ul>
<li>主程序已经生成好了，我们只需要写自己的逻辑</li>
<li>resources 文件夹中的目录结构
<ul>
<li>static：保存所有的静态资源；css js image</li>
<li>templates：保存所有的模板页面；（spring boot 默认 jar 包使用嵌入式的 tomcat，默认不支持 JSP 页面）；可以使用模板引擎（freemarker、thymeleaf）</li>
<li>application.properties：Spring Boot 应用的配置文件，可以修改一些默认配置</li>
</ul>
</li>
</ul>
<h1 id="二-配置文件"><a class="markdownIt-Anchor" href="#二-配置文件">#</a> 二、配置文件</h1>
<h2 id="1-配置文件"><a class="markdownIt-Anchor" href="#1-配置文件">#</a> 1. 配置文件</h2>
<p>SpringBoot 使用一个全局配置文件，配置文件名是固定的；</p>
<ul>
<li>application.properties</li>
<li>application.yml</li>
</ul>
<p>配置文件的作用：修改 springboot 自动配置的默认值；springboot 在底层都给我们配置好了；</p>
<p>YAML(YAML Ain’t Markup Language)</p>
<p>​		YAML A Markup Language：是一个标记语言</p>
<p>​		YAML isn’t Markup Language：不是一个标记语言</p>
<p>标记语言：</p>
<p>​		以前的配置文件，大多都使用 xxx.xml 文件；</p>
<p>​		YAML：<mark>以数据为中心</mark>，比 json、xml 等更适合做配置文件；</p>
<p>​		YAML：配置列子</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">server:</span><br><span class="line">  port: <span class="number">8081</span></span><br></pre></td></tr></table></figure>
<p>​		XML：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;server&gt;</span><br><span class="line">	&lt;port&gt;<span class="number">8081</span>&lt;/port&gt;</span><br><span class="line">&lt;/server&gt;</span><br></pre></td></tr></table></figure>
<h2 id="2-yaml语法"><a class="markdownIt-Anchor" href="#2-yaml语法">#</a> 2. YAML 语法</h2>
<h3 id="21-基本语法"><a class="markdownIt-Anchor" href="#21-基本语法">#</a> 2.1 基本语法</h3>
<p>k:(空格) v：表示一对键值对（空格必须有）；</p>
<p>以空格的缩进来控制层级关系；只要是左对齐的一列数据，都是同一层级的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">server:</span><br><span class="line">	port: <span class="number">8081</span></span><br><span class="line">    path: /hello</span><br></pre></td></tr></table></figure>
<p>属性和值也是大小写没敢；</p>
<h3 id="22-值的写法"><a class="markdownIt-Anchor" href="#22-值的写法">#</a> 2.2 值的写法</h3>
<h4 id="字面量普通的值数字字符串布尔"><a class="markdownIt-Anchor" href="#字面量普通的值数字字符串布尔">#</a> 字面量：普通的值（数字，字符串，布尔）</h4>
<p>​		k: v：字面量直接来写；</p>
<p>​				字符串默认不用加上单引号或者双引号；</p>
<p>​				“”：双引号：不会转义字符串里面的特殊字符；特殊字符会作为本身想表达的意思</p>
<p>​						name: “zhangsan \n lisi” 输出：zhangsan 换行 lisi</p>
<p>​				‘’：单引号：会转义特殊字符，</p>
<p>​						name: “zhangsan \n lisi” 输出：zhangsan \n lisi</p>
<h4 id="对象-map属性和值键值对"><a class="markdownIt-Anchor" href="#对象-map属性和值键值对">#</a> 对象、Map (属性和值)（键值对）</h4>
<p>​		k: v：在下一行来写对象的属性和值的关系；注意缩进</p>
<p>​				对象还是 k: v 的方式</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">friends:</span></span><br><span class="line">	<span class="attr">name:</span> <span class="string">zhansan</span></span><br><span class="line">    <span class="attr">age:</span> <span class="number">20</span></span><br></pre></td></tr></table></figure>
<p>行内写法：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">friends:</span> &#123;<span class="attr">name:</span> <span class="string">zhansan</span>,<span class="attr">age:</span> <span class="number">20</span>&#125;</span><br></pre></td></tr></table></figure>
<h4 id="数组list-set"><a class="markdownIt-Anchor" href="#数组list-set">#</a> 数组（List、Set）</h4>
<p>用 - 值表示数组中的一个元素</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pets:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">cat</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">dog</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">pig</span></span><br></pre></td></tr></table></figure>
<p>行内写法：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pets:</span> [<span class="string">cat</span>,<span class="string">dog</span>,<span class="string">pig</span>]</span><br></pre></td></tr></table></figure>
<h2 id="3-配置文件值注入"><a class="markdownIt-Anchor" href="#3-配置文件值注入">#</a> 3.  配置文件值注入</h2>
<p>配置文件：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">person:</span><br><span class="line">  lastName: zhangsan</span><br><span class="line">  age: 20</span><br><span class="line">  boss: false</span><br><span class="line">  birth: 2000/1/1</span><br><span class="line">  maps: &#123;k1: v1,k2: 12&#125;</span><br><span class="line">  lists:</span><br><span class="line">    - lisi</span><br><span class="line">    - zhaoliu</span><br><span class="line">  dog:</span><br><span class="line">    name: gou</span><br><span class="line">    age: 1</span><br></pre></td></tr></table></figure>
<p>javabean：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 将配置文件中的每一个属性的值，映射到这个组件中</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ConfigurationProperties</span> 告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定</span></span><br><span class="line"><span class="comment"> *      prefix = &quot;person&quot;：配置文件中哪个下面的属性进行匹配</span></span><br><span class="line"><span class="comment"> * 只有这个组件是容器中的组件，才能使用容器提供的<span class="doctag">@ConfigurationProperties</span>功能；</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;person&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String lastName;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> Boolean boss;</span><br><span class="line">    <span class="keyword">private</span> Date birth;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; maps;</span><br><span class="line">    <span class="keyword">private</span> List&lt;Object&gt; lists;</span><br><span class="line">    <span class="keyword">private</span> Dog dog;</span><br></pre></td></tr></table></figure>
<p>我们可以导入配置文件处理器，以后编写配置就有提示了</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 导入配置文件处理器 配置文件进行绑定就会有提示--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="31-properties配置文件在idea中默认utf-8可能会乱码"><a class="markdownIt-Anchor" href="#31-properties配置文件在idea中默认utf-8可能会乱码">#</a> 3.1 properties 配置文件在 idea 中默认 utf-8 可能会乱码</h3>
<p><img data-src="SpringBoot/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B9%B1%E7%A0%81.jpg" alt=""></p>
<h3 id="32-value获取值和configurationproperties获取值比较"><a class="markdownIt-Anchor" href="#32-value获取值和configurationproperties获取值比较">#</a> 3.2 @value 获取值和 @ConfigurationProperties 获取值比较</h3>
<table>
<thead>
<tr>
<th></th>
<th>@ConfigurationProperties</th>
<th>@value</th>
</tr>
</thead>
<tbody>
<tr>
<td>功能</td>
<td>批量注入配置文件中的属性</td>
<td>一个个指定</td>
</tr>
<tr>
<td>松散绑定（松散语法）</td>
<td>支持</td>
<td>不支持</td>
</tr>
<tr>
<td>SpEL</td>
<td>不支持</td>
<td>支持</td>
</tr>
<tr>
<td>JSR303 数据校验</td>
<td>支持</td>
<td>不支持</td>
</tr>
<tr>
<td>复杂类型封装</td>
<td>支持</td>
<td>不支持</td>
</tr>
</tbody>
</table>
<p>配置文件 yml 还是 properties 他们都能获取到值；</p>
<p>如果说，我们只是在某个业务逻辑中需要获取一下配置文件中的某项值，使用 @Value;</p>
<p>如果说，我们专门编写了一个 javaBean 来和配置文件进行映射，我们就直接使用 @ConfigurationProperties；</p>
<h3 id="33-配置文件注入值数据校验"><a class="markdownIt-Anchor" href="#33-配置文件注入值数据校验">#</a> 3.3 配置文件注入值数据校验</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 将配置文件中的每一个属性的值，映射到这个组件中</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ConfigurationProperties</span> 告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定</span></span><br><span class="line"><span class="comment"> *      prefix = &quot;person&quot;：配置文件中哪个下面的属性进行匹配</span></span><br><span class="line"><span class="comment"> * 只有这个组件是容器中的组件，才能使用容器提供的<span class="doctag">@ConfigurationProperties</span>功能；</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;person&quot;)</span></span><br><span class="line"><span class="meta">@Validated</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * &lt;bean class=&quot;person&quot;&gt;</span></span><br><span class="line"><span class="comment">     *      &lt;property name=&quot;lastName&quot; value=&quot;字面量/$&#123;key&#125;从环境变量、配置文件中获取值/#&#123;SpEL&#125;&quot;&gt;&lt;/property&gt;</span></span><br><span class="line"><span class="comment">     * &lt;/bean&gt;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">//@Value(&quot;&quot;)</span></span><br><span class="line">    <span class="comment">//lastName必须是邮箱格式的</span></span><br><span class="line">    <span class="meta">@Email</span></span><br><span class="line">    <span class="keyword">private</span> String lastName;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> Boolean boss;</span><br><span class="line">    <span class="keyword">private</span> Date birth;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; maps;</span><br><span class="line">    <span class="keyword">private</span> List&lt;Object&gt; lists;</span><br><span class="line">    <span class="keyword">private</span> Dog dog;</span><br></pre></td></tr></table></figure>
<h3 id="34-propertysourceimportresource"><a class="markdownIt-Anchor" href="#34-propertysourceimportresource">#</a> 3.4 @PropertySource&amp;@ImportResource</h3>
<p>@<strong>PropertySource</strong>：加载指定配置文件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 将配置文件中的每一个属性的值，映射到这个组件中</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ConfigurationProperties</span> 告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定</span></span><br><span class="line"><span class="comment"> *      prefix = &quot;person&quot;：配置文件中哪个下面的属性进行匹配</span></span><br><span class="line"><span class="comment"> * 只有这个组件是容器中的组件，才能使用容器提供的<span class="doctag">@ConfigurationProperties</span>功能；</span></span><br><span class="line"><span class="comment"> *  <span class="doctag">@ConfigurationProperties</span>(prefix = &quot;person&quot;)默认从全局配置文件中获取值</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@PropertySource(value = &#123;&quot;classpath:person.properties&quot;&#125;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;person&quot;)</span></span><br><span class="line"><span class="comment">//@Validated</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * &lt;bean class=&quot;person&quot;&gt;</span></span><br><span class="line"><span class="comment">     *      &lt;property name=&quot;lastName&quot; value=&quot;字面量/$&#123;key&#125;从环境变量、配置文件中获取值/#&#123;SpEL&#125;&quot;&gt;&lt;/property&gt;</span></span><br><span class="line"><span class="comment">     * &lt;/bean&gt;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">//@Value(&quot;&quot;)</span></span><br><span class="line">    <span class="comment">//lastName必须是邮箱格式的</span></span><br><span class="line">    <span class="comment">//@Email</span></span><br><span class="line">    <span class="keyword">private</span> String lastName;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> Boolean boss;</span><br></pre></td></tr></table></figure>
<p>@<strong>ImportResource</strong>：导入 spring 的配置文件，让配置文件里面的内容生效；</p>
<p>Spring Boot 里面没有 spring 的配置文件，我们自己编写的配置文件，也不能自动识别；</p>
<p>想让 spring 的配置文件生效，加载进来；@<strong>ImportResource</strong> 标注在一个配置类上</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ImportResource(locations = &quot;classpath:beans.xml&quot;)</span></span><br><span class="line">导入spring的配置文件让其生效</span><br></pre></td></tr></table></figure>
<p>不来编写 Spring 的配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;helloService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.study.springboot.service.HelloService&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>SpringBoot 推荐给容器中添加组件的方式；推荐使用全注解的方式</p>
<p>1、配置类 ==== Spring 配置文件</p>
<p>2、使用 @Bean 给容器添加组件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Configuration</span>： 指明当前类是一个配置类；就是来替代之前的spring配置文件</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 在配置文件中用&lt;bean&gt;&lt;/bean&gt;标签添加组件</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyAppConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//将方法的返回只添加到容器中：容器中这个组件默认的id就是方法名</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> HelloService <span class="title">helloService02</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;配置类@Bean组件添加成功&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> HelloService();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="4-配置文件占位符"><a class="markdownIt-Anchor" href="#4-配置文件占位符">#</a> 4. 配置文件占位符</h2>
<h3 id="41-随机数"><a class="markdownIt-Anchor" href="#41-随机数">#</a> 4.1 随机数</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">random.value、&#123;random.<span class="keyword">int</span>&#125;、$&#123;random.<span class="keyword">long</span>&#125;</span><br><span class="line"></span><br><span class="line">random.<span class="keyword">int</span>(<span class="number">10</span>)、&#123;random.<span class="keyword">int</span>[<span class="number">1024</span>, <span class="number">65536</span>]&#125;</span><br></pre></td></tr></table></figure>
<h3 id="42-占位符获取之前配置的值如果没有可以用指定默认值"><a class="markdownIt-Anchor" href="#42-占位符获取之前配置的值如果没有可以用指定默认值">#</a> 4.2 占位符获取之前配置的值，如果没有可以用：指定默认值</h3>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">person.last-name</span>=<span class="string">张三$&#123;random.uuid&#125;</span></span><br><span class="line"><span class="meta">person.age</span>=<span class="string">$&#123;random.int(28)&#125;</span></span><br><span class="line"><span class="meta">person.birth</span>=<span class="string">1999/1/1</span></span><br><span class="line"><span class="meta">person.boss</span>=<span class="string">true</span></span><br><span class="line"><span class="meta">person.maps.k1</span>=<span class="string">v1</span></span><br><span class="line"><span class="meta">person.maps.k2</span>=<span class="string">22</span></span><br><span class="line"><span class="meta">person.lists</span>=<span class="string">a,b,c</span></span><br><span class="line"><span class="meta">person.dog.name</span>=<span class="string">$&#123;person.hello:hello&#125;_dog</span></span><br><span class="line"><span class="meta">person.dog.age</span>=<span class="string">3</span></span><br></pre></td></tr></table></figure>
<h2 id="5-profile"><a class="markdownIt-Anchor" href="#5-profile">#</a> 5. Profile</h2>
<h3 id="51-多profile文件"><a class="markdownIt-Anchor" href="#51-多profile文件">#</a> 5.1 多 profile 文件</h3>
<p>我们在主配置文件编写的时候，文件名可以是 application-{profile}.properties/yml</p>
<p>默认使用 application.properties</p>
<h3 id="52-yml支持多文档块方式"><a class="markdownIt-Anchor" href="#52-yml支持多文档块方式">#</a> 5.2 yml 支持多文档块方式</h3>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8081</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">profiles:</span></span><br><span class="line">    <span class="attr">active:</span> <span class="string">dev</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8083</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">profiles:</span> <span class="string">dev</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8084</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">profiles:</span> <span class="string">prod</span></span><br></pre></td></tr></table></figure>
<h3 id="53-激活指定profile"><a class="markdownIt-Anchor" href="#53-激活指定profile">#</a> 5.3 激活指定 profile</h3>
<ol>
<li>
<p>在配置文件中指定  <code>spring.profiles.active=dev</code></p>
</li>
<li>
<p>命令行：</p>
<p>​	java -jar spring-boot-01-helloworld-1.0-SNAPSHOT.jar --spring.profiles.active=dev</p>
<p>​	可以直接在测试的时候，配置传入命令行参数</p>
</li>
<li>
<p>虚拟机参数；</p>
<p>-Dspring.profiles.active=dev</p>
</li>
</ol>
<h2 id="6-配置文件加载位置"><a class="markdownIt-Anchor" href="#6-配置文件加载位置">#</a> 6. 配置文件加载位置</h2>
<p>springboot 启动会自动扫描一下位置的 application.xml 或者 application.yml 文件作为 Springboot 的默认配置文件</p>
<p>-file: ./config/</p>
<p>-file: ./</p>
<p>-classpath: ./config/</p>
<p>-classpath: ./</p>
<p>优先级由高到低，高优先级的配置会覆盖低优先级的配置；</p>
<p>SpringBoot 会从这四个位置全部加载主配置文件；<strong>互补配置</strong>；</p>
<p><mark>我们还可以通过 spring.config.location 来改变默认的配置文件的位置</mark></p>
<p><strong>项目打包号以后，我们可以使用命令行参数的形式，启动项目的时候来指定配置文件的新位置；指定配置文件和默认加载的这些配置文件共同起作用形成互补配置；</strong></p>
<h2 id="7-外部配置加载顺序"><a class="markdownIt-Anchor" href="#7-外部配置加载顺序">#</a> 7. 外部配置加载顺序</h2>
<p><strong>SpringBoot 也可以从以下位置加载配置；优先级从高到低；高优先级的配置覆盖低优先级的配置，所有的配置会形成互补配置；</strong></p>
<ol>
<li>
<p><strong>命令行参数</strong></p>
<p>java -jar spring-boot-01-helloworld-1.0-SNAPSHOT.jar --server.port=8082 --server.context-path=/abc</p>
</li>
<li>
<p>来自：java:comp/env 的 JNDI 属性</p>
</li>
<li>
<p>Java 系统属性（System.getProperties ()）</p>
</li>
<li>
<p>操作系统环境变量</p>
</li>
<li>
<p>RandomValuePropertySource 配置的 random.* 属性值</p>
</li>
<li>
<p><strong>jar 包外部的 application-{profile}.properties 或 application-{profile}.yml (带 spring.profile) 配置文件</strong></p>
</li>
<li>
<p><strong>jar 包内部的 application-{profile}.properties 或 application-{profile}.yml (带 spring.profile) 配置文件</strong></p>
</li>
<li>
<p><strong>jar 包外部的 application.properties 或 application.yml (不带 spring.profile) 配置文件</strong></p>
</li>
<li>
<p><strong>jar 包内部的 application.properties 或 application.yml (不带 spring.profile) 配置文件</strong></p>
</li>
<li>
<p>@Configuration 注解上的 @PropertySource</p>
</li>
<li>
<p>通过 SpringApplication.setDefaultProperties 指定的默认属性</p>
</li>
</ol>
<p>所有支持的配置加载来源，参考<span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLWV4dGVybmFsLWNvbmZpZw==">官方文档</span></p>
<h2 id="8-自动配置原理"><a class="markdownIt-Anchor" href="#8-自动配置原理">#</a> 8. 自动配置原理</h2>
<p>配置文件到底能写什么？怎么写？自动配置原理；</p>
<p><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvYXBwZW5kaXgtYXBwbGljYXRpb24tcHJvcGVydGllcy5odG1sI2NvbW1vbi1hcHBsaWNhdGlvbi1wcm9wZXJ0aWVz">配置文件能配置的属性参照</span></p>
<h3 id="81-自动配置原理"><a class="markdownIt-Anchor" href="#81-自动配置原理">#</a> 8.1 自动配置原理</h3>
<p>1）springboot 启动的时候加载主配置类，开启了自动配置功能 ==@EnableAutoConfiguration==</p>
<p>2）@EnableAutoConfiguration 作用：</p>
<ul>
<li>
<p>利用 AutoConfigurationImportSelector 给容器中导入一些组件？</p>
</li>
<li>
<p>可以查找 selectImports () 方法的内容；</p>
</li>
<li>
<p>List<String> configurations = this.getCandidateConfigurations (annotationMetadata, attributes); 获取候选的配置</p>
<ul>
<li>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">SpringFactoriesLoader</span><span class="token punctuation">.</span><span class="token function">loadFactoryNames</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre>扫描所有jar包类路径下 META<span class="token operator">-</span>INF<span class="token operator">/</span>spring<span class="token punctuation">.</span>factories</pre></td></tr><tr><td data-num="3"></td><td><pre>把扫描到的这些文件的内容包装成properties对象</pre></td></tr><tr><td data-num="4"></td><td><pre>从properties中获取到<span class="token class-name">EnableAutoConfiguration</span><span class="token punctuation">.</span><span class="token keyword">class</span>类<span class="token punctuation">(</span>类名<span class="token punctuation">)</span>对应的值，然后把他们添加到容器中</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span>code￼<span class="token number">28</span><span class="token operator">--</span><span class="token operator">></span></pre></td></tr></table></figure></li>
</ul>
<p>每一个这样的 xxxAutoConfiguration 类都是容器中的一个组件，都加入到容器中；用他们来自动配置；</p>
</li>
</ul>
<p>3）每一个自动配置类进行自动配置功能；</p>
<p>4）以 **HttpEncodingAutoConfiguration（Http 编码自动配置）** 为例解释自动配置原理；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span> <span class="comment">//表示这是一个配置类，以前编写的配置文件一样，也可以给容器中添加组件</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(HttpProperties.class)</span> <span class="comment">//启用指定类的ConfigurationProperties功能；将配置文件中对应的值和HttpProperties绑定起来；并把HttpProperties加入到IOC容器中</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)</span> <span class="comment">//spring底层@Conditional注解，根据不同的条件，如果满足的指定的条件，整个配置类里面的配置就会生效；判断当前应用是否为web应用，如果是，当前配置类生效</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(CharacterEncodingFilter.class)</span> <span class="comment">//判断当前项目有没有这个类 CharacterEncodingFilter；SpringMVC中进行乱码解决的过滤器；</span></span><br><span class="line"><span class="meta">@ConditionalOnProperty(prefix = &quot;spring.http.encoding&quot;, value = &quot;enabled&quot;, matchIfMissing = true)</span> <span class="comment">//判断配置文件中是否存在某个配置 spring.http.encoding.enabled；如果不存在，判断也是成立的； 即使我们配置文件不配置spring.http.encoding.enabled=true，也是默认生效的；</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpEncodingAutoConfiguration</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//他已经和springboot的配置文件映射了</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> HttpProperties.Encoding properties;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//只有一个有参构造器的情况下，参数的值就会从容器中拿</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HttpEncodingAutoConfiguration</span><span class="params">(HttpProperties properties)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.properties = properties.getEncoding();</span><br><span class="line">	&#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Bean</span>  <span class="comment">//给容器中添加一个组件，这个组件的某些值需要从properties中获取</span></span><br><span class="line">	<span class="meta">@ConditionalOnMissingBean</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> CharacterEncodingFilter <span class="title">characterEncodingFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		CharacterEncodingFilter filter = <span class="keyword">new</span> OrderedCharacterEncodingFilter();</span><br><span class="line">		filter.setEncoding(<span class="keyword">this</span>.properties.getCharset().name());</span><br><span class="line">		filter.setForceRequestEncoding(<span class="keyword">this</span>.properties.shouldForce(Type.REQUEST));</span><br><span class="line">		filter.setForceResponseEncoding(<span class="keyword">this</span>.properties.shouldForce(Type.RESPONSE));</span><br><span class="line">		<span class="keyword">return</span> filter;</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>​		根据当前不同的条件判断，决定这个配置类是否生效？</p>
<p>​		一旦这个配置类生效；这个配置类就会给容器中添加各种组件；这些组件的属性是从对应的 properties 类中获取的，这些类里面的每一个属性又是和配置文件绑定的；</p>
<p>5）所有在配置文件中能配置的属性都是在 xxxxProperties 类中封装着；配置文件能配什么就可以参照某个功能对应的这个属性类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;spring.http&quot;)</span> <span class="comment">//从配置文件中获取指定的值和bean的属性进行绑定</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpProperties</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Whether logging of (potentially sensitive) request details at DEBUG and TRACE level</span></span><br><span class="line"><span class="comment">	 * is allowed.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">boolean</span> logRequestDetails;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * HTTP encoding properties.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">final</span> Encoding encoding = <span class="keyword">new</span> Encoding();</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isLogRequestDetails</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.logRequestDetails;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setLogRequestDetails</span><span class="params">(<span class="keyword">boolean</span> logRequestDetails)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.logRequestDetails = logRequestDetails;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Encoding <span class="title">getEncoding</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.encoding;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Configuration properties for http encoding.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Encoding</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;</span><br></pre></td></tr></table></figure>
<p>精髓：</p>
<p>​		<strong>1）SpringBoot 启动会加载大量的自动配置类</strong></p>
<p>​		<strong>2）看我们需要的功能有没有 SpringBoot 默认写好的自动配置类；</strong></p>
<p>​		<strong>3）我们再来看这个自动配置类中到底配置了哪些组件；（只要我们要用的组件有，我们就不需要再来配置了）</strong></p>
<p>​		<strong>4）给容器中自动配置类添加组件的时候，会从 properties 类中获取某些属性。我们就可以在配置文件中指定这些属性的值；</strong></p>
<p>xxxAutoConfiguration：自动配置类；</p>
<p>给容器中添加组件</p>
<p>xxxProperties：封装配置文件中相关属性；</p>
<h3 id="82-细节"><a class="markdownIt-Anchor" href="#82-细节">#</a> 8.2 细节</h3>
<h4 id="821-conditional派生注解spring注解版原生的conditional作用"><a class="markdownIt-Anchor" href="#821-conditional派生注解spring注解版原生的conditional作用">#</a> 8.2.1 @Conditional 派生注解（Spring 注解版原生的 @Conditional 作用）</h4>
<p>作用：必须是 @Conditional 指定的条件成立，才给容器中添加组件，配置里面的所有内容才生效；</p>
<table>
<thead>
<tr>
<th>@Conditional 注解扩展</th>
<th>作用（判断是否满足当前指定条件）</th>
</tr>
</thead>
<tbody>
<tr>
<td>@ConditionalOnJava</td>
<td>系统的 java 版本是否符合要求</td>
</tr>
<tr>
<td>@ConditionalOnBean</td>
<td>容器中存在指定 Bean</td>
</tr>
<tr>
<td>@ConditionalOnMissingBean</td>
<td>容器中不存在指定 Bean</td>
</tr>
<tr>
<td>@ConditionalOnExpression</td>
<td>满足 SpEL 表达式</td>
</tr>
<tr>
<td>@ConditionalOnClass</td>
<td>系统中有指定的类</td>
</tr>
<tr>
<td>@ConditionalOnMisssingClass</td>
<td>系统中没有指定的类</td>
</tr>
<tr>
<td>@ConditionalOnSingleCandidate</td>
<td>容器中只有一个指定的 Bean, 或者这个 Bean 是首选 Bean</td>
</tr>
<tr>
<td>@ConditionalOnProperty</td>
<td>系统中指定的属性是否有指定的值</td>
</tr>
<tr>
<td>@ConditionalOnResource</td>
<td>类路径下是否存在指定资源文件</td>
</tr>
<tr>
<td>@ConditionalOnWebApplication</td>
<td>当前是 Web 环境</td>
</tr>
<tr>
<td>@ConditionalOnNotWebApplication</td>
<td>当前不是 Web 环境</td>
</tr>
<tr>
<td>@ConditionalOnJndi</td>
<td>JNDI 存在指定项</td>
</tr>
</tbody>
</table>
<p><strong>自动配置类必须在一定条件下才能生效；</strong></p>
<p>我们怎么知道哪些自动配置类生效？</p>
<p>可以通过启动 debug=true 属性，来让控制台打印自动配置报告；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">============================</span><br><span class="line">CONDITIONS EVALUATION REPORT</span><br><span class="line">============================</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Positive matches:(自动配置类启用的)</span><br><span class="line">-----------------</span><br><span class="line"></span><br><span class="line">   AopAutoConfiguration matched:</span><br><span class="line">      - <span class="meta">@ConditionalOnProperty</span> (spring.aop.auto=<span class="keyword">true</span>) matched (OnPropertyCondition)</span><br><span class="line"></span><br><span class="line">   AopAutoConfiguration.ClassProxyingConfiguration matched:</span><br><span class="line">      - <span class="meta">@ConditionalOnMissingClass</span> did not find unwanted <span class="class"><span class="keyword">class</span> &#x27;<span class="title">org</span>.<span class="title">aspectj</span>.<span class="title">weaver</span>.<span class="title">Advice</span>&#x27; (<span class="title">OnClassCondition</span>)</span></span><br><span class="line"><span class="class">      - @<span class="title">ConditionalOnProperty</span> (<span class="title">spring</span>.<span class="title">aop</span>.<span class="title">proxy</span>-<span class="title">target</span>-<span class="title">class</span></span>=<span class="keyword">true</span>) matched (OnPropertyCondition)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Negative matches:(没有启用，没有匹配成功的自动配置类)</span><br><span class="line">-----------------</span><br><span class="line"></span><br><span class="line">   ActiveMQAutoConfiguration:</span><br><span class="line">      Did not match:</span><br><span class="line">         - <span class="meta">@ConditionalOnClass</span> did not find required <span class="class"><span class="keyword">class</span> &#x27;<span class="title">javax</span>.<span class="title">jms</span>.<span class="title">ConnectionFactory</span>&#x27; (<span class="title">OnClassCondition</span>)</span></span><br><span class="line"><span class="class"></span></span><br></pre></td></tr></table></figure>
<h1 id="三-日志"><a class="markdownIt-Anchor" href="#三-日志">#</a> 三、日志</h1>
<h2 id="1-日志框架"><a class="markdownIt-Anchor" href="#1-日志框架">#</a> 1. 日志框架</h2>
<p>小张，开发一个大型系统；</p>
<p>​		1、System.out.println (&quot;&quot;); 将关键数据打印在控制台；去掉？写在一个文件？</p>
<p>​		2、框架来记录系统的一些运行时信息；日志框架；zhanglogging.jar;</p>
<p>​		3、高大上的几个功能？异步模式？自动归档？xxx?zhanglogging-good.jar?</p>
<p>​		4、将以前框架卸下？换上新的框架，重新修改之前相关的 API；zhanglogging-perfect.jar;</p>
<p>​		5、JDBC— 数据库驱动；</p>
<p>​				写了一个统一的接口层；日志门面（日志的一个抽象层）；logging-abstract.jar;</p>
<p>​				给项目中导入具体的日志实现就行了；我们之前的日志框架都是实现的抽象层；</p>
<p><strong>市面上的日志框架；</strong></p>
<p>JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…</p>
<table>
<thead>
<tr>
<th>日志门面（日志的抽象层）</th>
<th>日志实现</th>
</tr>
</thead>
<tbody>
<tr>
<td><s>JCL(Jakarta Commons Logging)</s>   SLF4j(Simple Logging Facade for Java)  <s>Jboss-logging</s></td>
<td>Log4j  JUL(JAVA.UTIL.LOGGING)  Log4j2  Logback</td>
</tr>
</tbody>
</table>
<p>左边选一个门面（抽象层），右边来选一个实现；</p>
<p>日志门面：SLF4j；</p>
<p>日志实现：Logback；</p>
<p>SpringBoot：底层是 Spring 框架，Spring 框架默认是 JCL；</p>
<p>​		<strong>SpringBoot 选用 SLF4j 和 LogBack;</strong></p>
<h2 id="2-sel4j使用"><a class="markdownIt-Anchor" href="#2-sel4j使用">#</a> 2. SEL4j 使用</h2>
<h3 id="21-如何在系统中使用slf4j"><a class="markdownIt-Anchor" href="#21-如何在系统中使用slf4j">#</a> 2.1 如何在系统中使用 SLF4j</h3>
<p>以后开发的时候，日志记录方法的调用，不应该直接调用日志的实现类，而是调用日志抽象层里面的方法；</p>
<p>给系统里面导入 slf4j 的 jar 和 logback 的实现 jar</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloWorld</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    Logger logger = LoggerFactory.getLogger(HelloWorld.class);</span><br><span class="line">    logger.info(<span class="string">&quot;Hello World&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>图示：</p>
<p><img data-src="SpringBoot/concrete-bindings.png" alt=""></p>
<p>每一个日志的实现框架都有自己的配置文件。使用 slf4j 以后，<strong>配置文件还是做成日志实现框架自己本身的配置文件；</strong></p>
<h3 id="22-遗留问题"><a class="markdownIt-Anchor" href="#22-遗留问题">#</a> 2.2 遗留问题</h3>
<p>a（slf4j+logback）：Spring（commons-logging）、Hibernate（Jboss-logging）、Mybatis、xxxx</p>
<p>统一日志，即使是别的框架和我一起统一使用 slf4j 进行输出？</p>
<p><img data-src="SpringBoot/legacy.png" alt=""></p>
<p><strong>如何让系统中所有的日志统一到 slf4j；</strong></p>
<p><mark>1、将系统中其他日志框架先排除出去；</mark></p>
<p><mark>2、用中间包来替换缘由的日志框架；</mark></p>
<p><mark>3、我们导入 slf4j 其他的实现；</mark></p>
<h3 id="23-springboot日志关系"><a class="markdownIt-Anchor" href="#23-springboot日志关系">#</a> 2.3 SpringBoot 日志关系</h3>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.2.5.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>SpringBoot 使用它来做日志功能</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-logging<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.2.5.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>底层依赖关系</p>
<p><img data-src="SpringBoot/springboot-log.jpg" alt=""></p>
<p>总结：</p>
<p>​		1）SpringBoot 底层也是使用 slf4j+logback 的方式进行日志记录</p>
<p>​		2）SpringBoot 也把其他的日志都替换成了 slf4j</p>
<p>​		3）中间替换包？</p>
<p><img data-src="SpringBoot/logger-transfer.jpg" alt=""></p>
<p>​		4）如果我们要引入其他框架？一定要把这个框架的默认日志依赖移除掉？</p>
<h3 id="24-日志使用"><a class="markdownIt-Anchor" href="#24-日志使用">#</a> 2.4 日志使用</h3>
<h4 id="241-默认配置"><a class="markdownIt-Anchor" href="#241-默认配置">#</a> 2.4.1 默认配置</h4>
<p>SpringBoot 默认配置好了日志；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//记录器</span></span><br><span class="line">Logger logger = LoggerFactory.getLogger(getClass());</span><br><span class="line"></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">contextLoads</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//日志的级别</span></span><br><span class="line">    <span class="comment">//由低到高 trace&lt;debug&lt;info&lt;warn&lt;error</span></span><br><span class="line">    <span class="comment">//可以调整需要输出的日志级别；日志就只会在这个级别及以后的高级别生效</span></span><br><span class="line">    logger.trace(<span class="string">&quot;trace log ...&quot;</span>);</span><br><span class="line">    logger.debug(<span class="string">&quot;debug log ...&quot;</span>);</span><br><span class="line">    <span class="comment">//springboot默认给我们使用的是info级别的,没有指定级别就用springboot默认规定的级别；root级别</span></span><br><span class="line">    logger.info(<span class="string">&quot;info log ...&quot;</span>);</span><br><span class="line">    logger.warn(<span class="string">&quot;warn log ...&quot;</span>);</span><br><span class="line">    logger.error(<span class="string">&quot;error log ...&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>日志文件格式：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">日志输出格式：</span><br><span class="line">		%d表示日期时间，</span><br><span class="line">		%thread表示线程名，</span><br><span class="line">		%-5level：级别从左显示<span class="number">5</span>个字符宽度</span><br><span class="line">		%logger&#123;<span class="number">50</span>&#125; 表示logger名字最长<span class="number">50</span>个字符，否则按照句点分割。 </span><br><span class="line">		%msg：日志消息，</span><br><span class="line">		%n是换行符</span><br><span class="line">    </span><br><span class="line">    %d&#123;yyyy-MM-dd HH:mm:ss.SSS&#125; [%thread] %-5level %logger&#123;<span class="number">50</span>&#125; - %msg%n</span><br></pre></td></tr></table></figure>
<p>SpringBoot 修改日志的默认配置</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">logging.level.com.study</span>=<span class="string">trace</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 不指定路径在当前项目下生成springboot.log</span></span><br><span class="line"><span class="comment"># 可以指定完整的路径</span></span><br><span class="line"><span class="comment"># logging.file.name=springboot.log</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 在当前磁盘的根路径下spring文件夹和里面的log文件夹；使用spring.log作为默认文件</span></span><br><span class="line"><span class="meta">logging.file.path</span>=<span class="string">/spring/log</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 在控制台输出的日志格式</span></span><br><span class="line"><span class="meta">logging.pattern.console</span>=<span class="string">%d&#123;yyyy-MM-dd HH:mm:ss.SSS&#125; [%thread] %-5level %logger&#123;50&#125; - %msg%n</span></span><br><span class="line"><span class="comment"># 指定文件中日志的输出格式</span></span><br><span class="line"><span class="meta">logging.pattern.file</span>=<span class="string">%d&#123;yyyy-MM-dd HH:mm:ss.SSS&#125; [%thread] %-5level %logger&#123;50&#125; - %msg%n</span></span><br></pre></td></tr></table></figure>
<h4 id="242-指定配置"><a class="markdownIt-Anchor" href="#242-指定配置">#</a> 2.4.2 指定配置</h4>
<p>给类路径下放上每个日志框架自己的配置文件即可；SpringBoot 就不使用他默认配置的了</p>
<table>
<thead>
<tr>
<th style="text-align:left">Logging System</th>
<th style="text-align:left">Customization</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Logback</td>
<td style="text-align:left"><code>logback-spring.xml</code> ,  <code>logback-spring.groovy</code> ,  <code>logback.xml</code> , or  <code>logback.groovy</code></td>
</tr>
<tr>
<td style="text-align:left">Log4j2</td>
<td style="text-align:left"><code>log4j2-spring.xml</code>  or  <code>log4j2.xml</code></td>
</tr>
<tr>
<td style="text-align:left">JDK (Java Util Logging)</td>
<td style="text-align:left"><code>logging.properties</code></td>
</tr>
</tbody>
</table>
<p>logback.xml：直接就被日志框架识别了；</p>
<p>logback-spring.xml：日志框架就不直接加载日志的配置项，由 SpringBoot 解析日志配置，可以使用 springboot 的高级 profile 功能</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">springProfile</span> <span class="attr">name</span>=<span class="string">&quot;staging&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- configuration to be enabled when the &quot;staging&quot; profile is active --&gt;</span></span><br><span class="line">    可以指定某段配置只在某个环境下生效</span><br><span class="line"><span class="tag">&lt;/<span class="name">springProfile</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">&quot;CONSOLE&quot;</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.core.ConsoleAppender&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">springProfile</span> <span class="attr">name</span>=<span class="string">&quot;dev&quot;</span>&gt;</span></span><br><span class="line">    	<span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d&#123;yyyy-MM-dd HH:mm:ss.SSS&#125; [%thread] %-5level %logger&#123;50&#125; - %msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">springProfile</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">springProfile</span> <span class="attr">name</span>=<span class="string">&quot;!dev&quot;</span>&gt;</span></span><br><span class="line">    	<span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d&#123;yyyy-MM-dd HH:mm:ss.SSS&#125; === [%thread] === %-5level %logger&#123;50&#125; - %msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">springProfile</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="25-日志框架切换"><a class="markdownIt-Anchor" href="#25-日志框架切换">#</a> 2.5 日志框架切换</h3>
<p>切换为 log4j2：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-logging<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">      <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-log4j2<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h1 id="四-web开发"><a class="markdownIt-Anchor" href="#四-web开发">#</a> 四、Web 开发</h1>
<h2 id="1-简介"><a class="markdownIt-Anchor" href="#1-简介">#</a> 1. 简介</h2>
<p>使用 Spring Boot；</p>
<p><strong>1）创建 SpringBoot 应用，选中我们需要的模块；</strong></p>
<p><strong>2）SpringBoot 已经默认将这些场景配置好了，只需要在配置文件中指定少量配置就可以运行起来；</strong></p>
<p><strong>3）自己编写业务代码；</strong></p>
<p><strong>自动配置原理？</strong></p>
<p>这个场景 SpringBoot 帮我们配置了什么？能不能修改？能修改哪些配置？能不能扩展？xxx</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">xxxxAutoConfiguration：帮我们给容器中自动配置组件</span><br><span class="line">xxxxProperties：配置类来封装配置文件的内容</span><br></pre></td></tr></table></figure>
<h2 id="2-springboot对静态资源的映射规则"><a class="markdownIt-Anchor" href="#2-springboot对静态资源的映射规则">#</a> 2. SpringBoot 对静态资源的映射规则</h2>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;spring.resources&quot;, ignoreUnknownFields = false)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ResourceProperties</span> </span>&#123;</span><br><span class="line">    <span class="comment">//可以设置和资源有关的参数，缓存时间等</span></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addResourceHandlers</span><span class="params">(ResourceHandlerRegistry registry)</span> </span>&#123;</span><br><span class="line">   <span class="keyword">if</span> (!<span class="keyword">this</span>.resourceProperties.isAddMappings()) &#123;</span><br><span class="line">      logger.debug(<span class="string">&quot;Default resource handling disabled&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   Duration cachePeriod = <span class="keyword">this</span>.resourceProperties.getCache().getPeriod();</span><br><span class="line">   CacheControl cacheControl = <span class="keyword">this</span>.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();</span><br><span class="line">   <span class="keyword">if</span> (!registry.hasMappingForPattern(<span class="string">&quot;/webjars/**&quot;</span>)) &#123;</span><br><span class="line">      customizeResourceHandlerRegistration(registry.addResourceHandler(<span class="string">&quot;/webjars/**&quot;</span>)</span><br><span class="line">            .addResourceLocations(<span class="string">&quot;classpath:/META-INF/resources/webjars/&quot;</span>)</span><br><span class="line">            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));</span><br><span class="line">   &#125;</span><br><span class="line">   String staticPathPattern = <span class="keyword">this</span>.mvcProperties.getStaticPathPattern();</span><br><span class="line">   <span class="keyword">if</span> (!registry.hasMappingForPattern(staticPathPattern)) &#123;</span><br><span class="line">      customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)</span><br><span class="line">            .addResourceLocations(getResourceLocations(<span class="keyword">this</span>.resourceProperties.getStaticLocations()))</span><br><span class="line">            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//配置欢迎页映射</span></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line">		<span class="function"><span class="keyword">public</span> WelcomePageHandlerMapping <span class="title">welcomePageHandlerMapping</span><span class="params">(ApplicationContext applicationContext,</span></span></span><br><span class="line"><span class="params"><span class="function">				FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider)</span> </span>&#123;</span><br><span class="line">			WelcomePageHandlerMapping welcomePageHandlerMapping = <span class="keyword">new</span> WelcomePageHandlerMapping(</span><br><span class="line">					<span class="keyword">new</span> TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),</span><br><span class="line">					<span class="keyword">this</span>.mvcProperties.getStaticPathPattern());</span><br><span class="line">			welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));</span><br><span class="line">			<span class="keyword">return</span> welcomePageHandlerMapping;</span><br><span class="line">		&#125;</span><br></pre></td></tr></table></figure>
<p>1）所有 /webjars/**，都去 classpath:/META-INF/resources/webjars/ 找资源</p>
<p>​		webjars：以 jar 包的方式引入静态资源；</p>
<p>​		<span class="exturl" data-url="aHR0cHM6Ly93d3cud2ViamFycy5vcmcv">https://www.webjars.org/</span></p>
<p><img data-src="SpringBoot/webjar.jpg" alt=""></p>
<p>​		localhost:8080/webjars/jquery/3.4.1/jquery.js</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 引入jQuery-webjar --&gt;</span>在访问的时候只需要写webjars下面的资源名称即可</span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.webjars<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jquery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.4.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2）“/**” 访问当前项目的任何资源，（静态资源的文件夹）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&quot;classpath:/META-INF/resources/&quot;,</span><br><span class="line">&quot;classpath:/resources/&quot;,</span><br><span class="line">&quot;classpath:/static/&quot;, </span><br><span class="line">&quot;classpath:/public/&quot; ,</span><br><span class="line">&quot;/&quot;：当前项目的根路径</span><br></pre></td></tr></table></figure>
<p>localhost:8080/abc === 去静态资源文件夹里面找 abc</p>
<p>3）欢迎页；静态资源文件夹下面的所有 index.html 页面；被 &quot;/**&quot; 映射；</p>
<p>​		localhost:8080/  找 index 页面</p>
<h2 id="3-模板引擎"><a class="markdownIt-Anchor" href="#3-模板引擎">#</a> 3. 模板引擎</h2>
<p>JSP、Velocity、Freemarker、Thymeleaf</p>
<p><img data-src="SpringBoot/%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E.jpg" alt=""></p>
<p>SpringBoot 推荐的 Thymeleaf；</p>
<p>语法更简单，功能更强大；</p>
<h3 id="31-引入thymeleaf"><a class="markdownIt-Anchor" href="#31-引入thymeleaf">#</a> 3.1 引入 Thymeleaf</h3>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-thymeleaf<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">切换thymeleaf版本</span><br><span class="line"><span class="tag">&lt;<span class="name">properties</span>&gt;</span>     </span><br><span class="line">    <span class="tag">&lt;<span class="name">thymeleaf.version</span>&gt;</span>3.0.11.RELEASE<span class="tag">&lt;/<span class="name">thymeleaf.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">thymeleaf-layout-dialect.version</span>&gt;</span>2.4.1<span class="tag">&lt;/<span class="name">thymeleaf-layout-dialect.version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="32-thymeleaf使用语法"><a class="markdownIt-Anchor" href="#32-thymeleaf使用语法">#</a> 3.2 Thymeleaf 使用 &amp; 语法</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;spring.thymeleaf&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThymeleafProperties</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_PREFIX = <span class="string">&quot;classpath:/templates/&quot;</span>;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String DEFAULT_SUFFIX = <span class="string">&quot;.html&quot;</span>;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Whether to check that the template exists before rendering it.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">boolean</span> checkTemplate = <span class="keyword">true</span>;</span><br></pre></td></tr></table></figure>
<p>只要我们把 HTML 页面放在 classpath:/templates/，thymeleaf 就能自动渲染</p>
<p>1、导入 themeleaf 的名称空间</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2、使用 themeleaf 语法</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>success<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- th:text 将div里面的文本内容设置为 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;hello&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="33-语法规则"><a class="markdownIt-Anchor" href="#33-语法规则">#</a> 3.3 语法规则</h3>
<p>1）th:text；改变当前元素的文本规则；</p>
<p>​		th: 任意 html 属性；来替换原生属性的值</p>
<p><img data-src="SpringBoot/thymeleaf%E8%AF%AD%E6%B3%95.png" alt=""></p>
<p>2）表达式？</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">Simple</span> <span class="string">expressions: （表达式语法）</span></span><br><span class="line">    <span class="attr">Variable</span> <span class="string">Expressions: $&#123;...&#125; ：获取变量值；OGNL</span></span><br><span class="line">    	<span class="attr">1）获取对象属性、调用方法</span></span><br><span class="line">    	<span class="attr">2）使用内置的基本对象</span></span><br><span class="line"><span class="comment">            #ctx : the context object.</span></span><br><span class="line"><span class="comment">            #vars: the context variables.</span></span><br><span class="line"><span class="comment">            #locale : the context locale.</span></span><br><span class="line"><span class="comment">            #request : (only in Web Contexts) the HttpServletRequest object.</span></span><br><span class="line"><span class="comment">            #response : (only in Web Contexts) the HttpServletResponse object.</span></span><br><span class="line"><span class="comment">            #session : (only in Web Contexts) the HttpSession object.</span></span><br><span class="line"><span class="comment">            #servletContext : (only in Web Contexts) the ServletContext object.</span></span><br><span class="line">            <span class="attr">$&#123;session.foo&#125;</span></span><br><span class="line">        <span class="attr">3）内置的一些工具对象：</span></span><br><span class="line"><span class="comment">            #execInfo : information about the template being processed.</span></span><br><span class="line"><span class="comment">            #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #&#123;…&#125; syntax.</span></span><br><span class="line"><span class="comment">            #uris : methods for escaping parts of URLs/URIs</span></span><br><span class="line"><span class="comment">            #dates : methods for java.util.Date objects: formatting, component extraction, etc.</span></span><br><span class="line"><span class="comment">            #calendars : analogous to #dates , but for java.util.Calendar objects.</span></span><br><span class="line"><span class="comment">            #numbers : methods for formatting numeric objects.</span></span><br><span class="line"><span class="comment">            #strings : methods for String objects: contains, startsWith, prepending/appending, etc.</span></span><br><span class="line"><span class="comment">            #objects : methods for objects in general.</span></span><br><span class="line"><span class="comment">            #bools : methods for boolean evaluation.</span></span><br><span class="line"><span class="comment">            #arrays : methods for arrays.</span></span><br><span class="line"><span class="comment">            #lists : methods for lists.</span></span><br><span class="line"><span class="comment">            #sets : methods for sets.</span></span><br><span class="line"><span class="comment">            #maps : methods for maps.</span></span><br><span class="line"><span class="comment">            #aggregates : methods for creating aggregates on arrays or collections.</span></span><br><span class="line"><span class="comment">            #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).</span></span><br><span class="line">            </span><br><span class="line">    <span class="attr">Selection</span> <span class="string">Variable Expressions: *&#123;...&#125; ：选择表达式：功能上和$&#123;&#125;是一样的</span></span><br><span class="line">    	<span class="meta">补充：配合</span> <span class="string">th:object=&quot;$&#123;session.user&#125;&quot;</span></span><br><span class="line">    	<span class="meta">&lt;div</span> <span class="string">th:object=&quot;$&#123;session.user&#125;&quot;&gt;</span></span><br><span class="line">            <span class="meta">&lt;p&gt;Name</span>: <span class="string">&lt;span th:text=&quot;*&#123;firstName&#125;&quot;&gt;Sebastian&lt;/span&gt;.&lt;/p&gt;</span></span><br><span class="line">            <span class="meta">&lt;p&gt;Surname</span>: <span class="string">&lt;span th:text=&quot;*&#123;lastName&#125;&quot;&gt;Pepper&lt;/span&gt;.&lt;/p&gt;</span></span><br><span class="line">            <span class="meta">&lt;p&gt;Nationality</span>: <span class="string">&lt;span th:text=&quot;*&#123;nationality&#125;&quot;&gt;Saturn&lt;/span&gt;.&lt;/p&gt;</span></span><br><span class="line">        <span class="attr">&lt;/div&gt;</span></span><br><span class="line">    <span class="attr">Message</span> <span class="string">Expressions: #&#123;...&#125; ：获取国际化内容</span></span><br><span class="line">    <span class="attr">Link</span> <span class="string">URL Expressions: @&#123;...&#125; ：定义URL</span></span><br><span class="line">    	<span class="meta">@&#123;/order/process(execId</span>=<span class="string">$&#123;execId&#125;,execType=&#x27;FAST&#x27;)&#125;</span></span><br><span class="line">    <span class="attr">Fragment</span> <span class="string">Expressions: ~&#123;...&#125; ：片段引用表达式</span></span><br><span class="line">    	<span class="meta">&lt;div</span> <span class="string">th:insert=&quot;~&#123;commons :: main&#125;&quot;&gt;...&lt;/div&gt;</span></span><br><span class="line"><span class="attr">Literals（字面量）</span></span><br><span class="line">    <span class="attr">Text</span> <span class="string">literals: &#x27;one text&#x27; , &#x27;Another one!&#x27; ,…</span></span><br><span class="line">    <span class="attr">Number</span> <span class="string">literals: 0 , 34 , 3.0 , 12.3 ,…</span></span><br><span class="line">    <span class="attr">Boolean</span> <span class="string">literals: true , false</span></span><br><span class="line">    <span class="attr">Null</span> <span class="string">literal: null</span></span><br><span class="line">    <span class="attr">Literal</span> <span class="string">tokens: one , sometext , main ,…</span></span><br><span class="line"><span class="attr">Text</span> <span class="string">operations:（文本操作）</span></span><br><span class="line">    <span class="attr">String</span> <span class="string">concatenation: +</span></span><br><span class="line">    <span class="attr">Literal</span> <span class="string">substitutions: |The name is $&#123;name&#125;|</span></span><br><span class="line"><span class="attr">Arithmetic</span> <span class="string">operations:（数学运算）</span></span><br><span class="line">    <span class="attr">Binary</span> <span class="string">operators: + , - , * , / , %</span></span><br><span class="line">    <span class="attr">Minus</span> <span class="string">sign (unary operator): -</span></span><br><span class="line"><span class="attr">Boolean</span> <span class="string">operations:（布尔运算）</span></span><br><span class="line">    <span class="attr">Binary</span> <span class="string">operators: and , or</span></span><br><span class="line">    <span class="attr">Boolean</span> <span class="string">negation (unary operator): ! , not</span></span><br><span class="line"><span class="attr">Comparisons</span> <span class="string">and equality:（比较运算）</span></span><br><span class="line">    <span class="attr">Comparators</span>: <span class="string">&gt; , &lt; , &gt;= , &lt;= ( gt , lt , ge , le )</span></span><br><span class="line">    <span class="attr">Equality</span> <span class="string">operators: == , != ( eq , ne )</span></span><br><span class="line"><span class="attr">Conditional</span> <span class="string">operators:（条件运算、三元运算）</span></span><br><span class="line">    <span class="meta">If-then</span>: <span class="string">(if) ? (then)</span></span><br><span class="line">    <span class="meta">If-then-else</span>: <span class="string">(if) ? (then) : (else)</span></span><br><span class="line">    <span class="attr">Default</span>: <span class="string">(value) ?: (defaultvalue)</span></span><br><span class="line"><span class="attr">Special</span> <span class="string">tokens:</span></span><br><span class="line"><span class="attr">Page</span> <span class="string">17 of 106No-Operation: _</span></span><br></pre></td></tr></table></figure>
<h2 id="4-springmvc自动配置"><a class="markdownIt-Anchor" href="#4-springmvc自动配置">#</a> 4. SpringMVC 自动配置</h2>
<p><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLXNwcmluZy1tdmM=">官方文档</span></p>
<h3 id="41-spring-mvc-auto-configuration"><a class="markdownIt-Anchor" href="#41-spring-mvc-auto-configuration">#</a> 4.1 Spring MVC Auto-configuration</h3>
<p>Spring Boot 自动配置好了 SpringMVC</p>
<p>以下是 SpringBoot 对 SpringMVC 的默认：</p>
<ul>
<li>
<p>Inclusion of  <code>ContentNegotiatingViewResolver</code>  and  <code>BeanNameViewResolver</code>  beans.</p>
<ul>
<li>自动配置了 ViewResolver (视图解析器：根据方法的返回值得到视图对象（View）, 视图对象决定如何渲染（转发？重定向？）)</li>
<li>ContentNegotiatingViewResolver：组合所有的视图解析器；</li>
<li>如何定制：<mark>我们可以自己给容器中添加一个视图解析器；自动的将其组合进来；</mark></li>
</ul>
</li>
<li>
<p>Support for serving static resources, including support for WebJars (covered <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLXNwcmluZy1tdmMtc3RhdGljLWNvbnRlbnQ=">later in this document</span>)).  静态资源文件夹路径和 webjars</p>
</li>
<li>
<p>自动注册了 of  <code>Converter</code> ,  <code>GenericConverter</code> , and  <code>Formatter</code>  beans.</p>
<ul>
<li>
<p>Converter：转换器；public String hello (User user)；类型转换使用 Converter</p>
</li>
<li>
<p>Formatter：格式化器；2020-3-3 === Date；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> FormattingConversionService <span class="title">mvcConversionService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    WebConversionService conversionService = <span class="keyword">new</span> WebConversionService(<span class="keyword">this</span>.mvcProperties.getDateFormat());</span><br><span class="line">    addFormatters(conversionService);</span><br><span class="line">    <span class="keyword">return</span> conversionService;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//日期格式化规则</span></span><br></pre></td></tr></table></figure>
<p><mark>自己添加的格式化转换器，我们只需要放在容器中即可</mark></p>
</li>
</ul>
</li>
<li>
<p>Support for  <code>HttpMessageConverters</code>  (covered <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLXNwcmluZy1tdmMtbWVzc2FnZS1jb252ZXJ0ZXJz">later in this document</span>).</p>
<ul>
<li>
<p>HttpMessageConverters：SpringMVC 用来转换 Http 请求和响应的；User — json</p>
</li>
<li>
<p>HttpMessageConverters 是从容器中确定的；获取所有的 HttpMessageConverters；</p>
<p><mark>自己给容器中添加 HttpMessageConverters，只需要将自己的组件注册容器中（@Bean, @Component）</mark></p>
</li>
</ul>
</li>
<li>
<p>Automatic registration of  <code>MessageCodesResolver</code>  (covered <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLXNwcmluZy1tZXNzYWdlLWNvZGVz">later in this document</span>).  定义错误代码生成规则</p>
</li>
<li>
<p>Static  <code>index.html</code>  support.  静态首页访问</p>
</li>
<li>
<p>Custom  <code>Favicon</code>  support (covered <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLXNwcmluZy1tdmMtZmF2aWNvbg==">later in this document</span>).  favicon.ico</p>
</li>
<li>
<p>Automatic use of a  <code>ConfigurableWebBindingInitializer</code>  bean (covered <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmctYm9vdC9kb2NzLzIuMi41LlJFTEVBU0UvcmVmZXJlbmNlL2h0bWwvc3ByaW5nLWJvb3QtZmVhdHVyZXMuaHRtbCNib290LWZlYXR1cmVzLXNwcmluZy1tdmMtd2ViLWJpbmRpbmctaW5pdGlhbGl6ZXI=">later in this document</span>).</p>
<p><mark>我们可以配置一个 ConfigurableWebBindingInitializer 来替换默认的；</mark></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">初始化WebDataBinder</span><br><span class="line">请求数据===JavaBean</span><br></pre></td></tr></table></figure>
<p><strong><span class="exturl" data-url="aHR0cDovL29yZy5zcHJpbmdmcmFtZXdvcmsuYm9vdC5hdXRvY29uZmlndXJlLndlYg==">org.springframework.boot.autoconfigure.web</span>；web 的所有自动配置场景</strong></p>
</li>
</ul>
<p>If you want to keep those Spring Boot MVC customizations and make more <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnNwcmluZy5pby9zcHJpbmcvZG9jcy81LjIuNC5SRUxFQVNFL3NwcmluZy1mcmFtZXdvcmstcmVmZXJlbmNlL3dlYi5odG1sI212Yw==">MVC customizations</span> (interceptors, formatters, view controllers, and other features), you can add your own  <code>@Configuration</code>  class of type  <code>WebMvcConfigurer</code>  but <strong>without</strong>  <code>@EnableWebMvc</code> .</p>
<p>If you want to provide custom instances of  <code>RequestMappingHandlerMapping</code> ,  <code>RequestMappingHandlerAdapter</code> , or  <code>ExceptionHandlerExceptionResolver</code> , and still keep the Spring Boot MVC customizations, you can declare a bean of type  <code>WebMvcRegistrations</code>  and use it to provide custom instances of those components.</p>
<p>If you want to take complete control of Spring MVC, you can add your own  <code>@Configuration</code>  annotated with  <code>@EnableWebMvc</code> , or alternatively add your own  <code>@Configuration</code> -annotated  <code>DelegatingWebMvcConfiguration</code>  as described in the Javadoc of  <code>@EnableWebMvc</code> .</p>
<h3 id="42-扩展springmvc"><a class="markdownIt-Anchor" href="#42-扩展springmvc">#</a> 4.2 扩展 SpringMVC</h3>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mvc:view-controller</span> <span class="attr">path</span>=<span class="string">&quot;/hello&quot;</span> <span class="attr">view-name</span>=<span class="string">&quot;success&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">mvc:interceptors</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">mvc:mapping</span> <span class="attr">path</span>=<span class="string">&quot;/hello&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">bean</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">mvc:interceptor</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mvc:interceptors</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><strong><mark>编写一个配置类（@Configuration），是 WebMvcConfigurerAdapter 类型；不能标注（@EnableWebMvc）</mark></strong></p>
<p>既保留了所有的自动配置，也能用我们扩展的配置；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用WebMvcConfigurer可以来扩展SpringMVC的功能</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyMvcConfig</span> <span class="keyword">implements</span> <span class="title">WebMvcConfigurer</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//浏览器发送 /study 请求，也来到success页面</span></span><br><span class="line">        registry.addViewController(<span class="string">&quot;/study&quot;</span>).setViewName(<span class="string">&quot;success&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>原理：</p>
<p>​		1）WebMvcAutoConfiguration 是 SpringMVC 的自动配置类</p>
<p>​		2）在做其他自动配置时会导入；@Import (EnableWebMvcConfiguration.class)</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">EnableWebMvcConfiguration</span> <span class="keyword">extends</span> <span class="title">DelegatingWebMvcConfiguration</span> <span class="keyword">implements</span> <span class="title">ResourceLoaderAware</span> </span>&#123;</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> WebMvcConfigurerComposite configurers = <span class="keyword">new</span> WebMvcConfigurerComposite();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//从容器中获取所有的WebMvcConfigurer</span></span><br><span class="line">	<span class="meta">@Autowired(required = false)</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setConfigurers</span><span class="params">(List&lt;WebMvcConfigurer&gt; configurers)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (!CollectionUtils.isEmpty(configurers)) &#123;</span><br><span class="line">			<span class="keyword">this</span>.configurers.addWebMvcConfigurers(configurers);</span><br><span class="line">            <span class="comment">//一个参考实现；将所有的WebMvcConfigurer相关配置一起调用；</span></span><br><span class="line">            <span class="comment">//@Override</span></span><br><span class="line">            <span class="comment">//public void addViewControllers(ViewControllerRegistry registry) &#123;</span></span><br><span class="line">            <span class="comment">//    for (WebMvcConfigurer delegate : this.delegates) &#123;</span></span><br><span class="line">            <span class="comment">//        delegate.addViewControllers(registry);</span></span><br><span class="line">            <span class="comment">//    &#125;</span></span><br><span class="line">            <span class="comment">//&#125;</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>​		3）容器中所有的 WebMvcConfiguration 都会一起起作用；</p>
<p>​		4）我们的配置也会被调用</p>
<p>​		效果：SpringMVC 的自动配置和我们的扩展配置都会起作用；</p>
<h3 id="43-全面接管springmvc"><a class="markdownIt-Anchor" href="#43-全面接管springmvc">#</a> 4.3 全面接管 SpringMVC</h3>
<p>SpringBoot 对 SpringMVC 的自动配置不需要了，所有都是我们自己配；所有的 SpringMVC 的自动配置都失效了</p>
<p><strong>我们需要在配置类中添加 @EnableWebMvc 即可；</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用WebMvcConfigurer可以来扩展SpringMVC的功能</span></span><br><span class="line"><span class="meta">@EnableWebMvc</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyMvcConfig</span> <span class="keyword">implements</span> <span class="title">WebMvcConfigurer</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//浏览器发送 /study 请求，也来到success页面</span></span><br><span class="line">        registry.addViewController(<span class="string">&quot;/study&quot;</span>).setViewName(<span class="string">&quot;success&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>原理：</p>
<p>为什么 @EnableWebMvc 自动配置就失效了；</p>
<p>1）EnableWebMvc 的核心</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Import(DelegatingWebMvcConfiguration.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> EnableWebMvc &#123;</span><br></pre></td></tr></table></figure>
<p>2）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DelegatingWebMvcConfiguration</span> <span class="keyword">extends</span> <span class="title">WebMvcConfigurationSupport</span> </span>&#123;</span><br></pre></td></tr></table></figure>
<p>3）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = Type.SERVLET)</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(&#123; Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class &#125;)</span></span><br><span class="line"><span class="comment">//容器中没有这个组件的时候，这个自动配置类才生效</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)</span></span><br><span class="line"><span class="meta">@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)</span></span><br><span class="line"><span class="meta">@AutoConfigureAfter(&#123; DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,</span></span><br><span class="line"><span class="meta">		ValidationAutoConfiguration.class &#125;</span></span><br></pre></td></tr></table></figure>
<p>4）@EnableWebMvc 将 WebMvcConfigurationSupport 组件导入进来了；</p>
<p>5）导入到的 WebMvcConfigurationSupport 只是 SpringMVC 最基本的功能；</p>
<h2 id="5-如何修改springboot的默认配置"><a class="markdownIt-Anchor" href="#5-如何修改springboot的默认配置">#</a> 5. 如何修改 SpringBoot 的默认配置</h2>
<p>模式：</p>
<p>​		1）SpringBoot 在自动配置很多组件的时候，先看容器中有没有用户自己配置的（@Bean、@Component）如果有就用用户配置的，如果没有，才自动配置；如果某些组件可以有多个（ViewResolver）将用户配置的和自己默认的组合起来；</p>
<p>​		2）在 SpringBoot 中会有非常多的 xxxConfigurer 帮助我们进行扩展配置；</p>
<p>​		3）在 SpringBoot 中会有很多的 xxxCustomizer 帮助我们进行配置；</p>
<h2 id="6-restfulcrud"><a class="markdownIt-Anchor" href="#6-restfulcrud">#</a> 6. RestfulCRUD</h2>
<h3 id="61-默认访问首页"><a class="markdownIt-Anchor" href="#61-默认访问首页">#</a> 6.1 默认访问首页</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyMvcConfig</span> <span class="keyword">implements</span> <span class="title">WebMvcConfigurer</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//浏览器发送 /study 请求，也来到success页面</span></span><br><span class="line">        registry.addViewController(<span class="string">&quot;/study&quot;</span>).setViewName(<span class="string">&quot;success&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> WebMvcConfigurer <span class="title">webMvcConfigurer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        WebMvcConfigurer mvcConfigurer = <span class="keyword">new</span> WebMvcConfigurer() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> </span>&#123;</span><br><span class="line">                registry.addViewController(<span class="string">&quot;/&quot;</span>).setViewName(<span class="string">&quot;login&quot;</span>);</span><br><span class="line">                registry.addViewController(<span class="string">&quot;/index.html&quot;</span>).setViewName(<span class="string">&quot;login&quot;</span>);</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="keyword">return</span> mvcConfigurer;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="62-国际化"><a class="markdownIt-Anchor" href="#62-国际化">#</a> 6.2 国际化</h3>
<p><strong>1）编写国际化配置文件</strong></p>
<p>2）使用 ResourceBundleMessageSource 管理国际化资源文件</p>
<p>3）在页面使用 fmt:message 去除国际化内容</p>
<p>步骤：</p>
<p>1）编写国际化配置文件，抽取页面需要显示的国际化消息</p>
<p><img data-src="SpringBoot/%E5%9B%BD%E9%99%85%E5%8C%96%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6.jpg" alt=""></p>
<p>2）SpringBoot 自动配置好了管理国际化资源文件的组件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableConfigurationProperties</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MessageSourceAutoConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Resource[] NO_RESOURCES = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Bean</span></span><br><span class="line">	<span class="meta">@ConfigurationProperties(prefix = &quot;spring.messages&quot;)</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> MessageSourceProperties <span class="title">messageSourceProperties</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">new</span> MessageSourceProperties();</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> MessageSource <span class="title">messageSource</span><span class="params">(MessageSourceProperties properties)</span> </span>&#123;</span><br><span class="line">		ResourceBundleMessageSource messageSource = <span class="keyword">new</span> ResourceBundleMessageSource();</span><br><span class="line">		<span class="keyword">if</span> (StringUtils.hasText(properties.getBasename())) &#123;</span><br><span class="line">            <span class="comment">//设计国际化资源文件的基础名（去掉语言国家代码的）</span></span><br><span class="line">			messageSource.setBasenames(StringUtils</span><br><span class="line">.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (properties.getEncoding() != <span class="keyword">null</span>) &#123;</span><br><span class="line">			messageSource.setDefaultEncoding(properties.getEncoding().name());</span><br><span class="line">		&#125;</span><br><span class="line">		messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());</span><br><span class="line">		Duration cacheDuration = properties.getCacheDuration();</span><br><span class="line">		<span class="keyword">if</span> (cacheDuration != <span class="keyword">null</span>) &#123;</span><br><span class="line">			messageSource.setCacheMillis(cacheDuration.toMillis());</span><br><span class="line">		&#125;</span><br><span class="line">		messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());</span><br><span class="line">		messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());</span><br><span class="line">		<span class="keyword">return</span> messageSource;</span><br><span class="line">	&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MessageSourceProperties</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Comma-separated list of basenames (essentially a fully-qualified classpath</span></span><br><span class="line"><span class="comment">	 * location), each following the ResourceBundle convention with relaxed support for</span></span><br><span class="line"><span class="comment">	 * slash based locations. If it doesn&#x27;t contain a package qualifier (such as</span></span><br><span class="line"><span class="comment">	 * &quot;org.mypackage&quot;), it will be resolved from the classpath root.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">private</span> String basename = <span class="string">&quot;messages&quot;</span>;  <span class="comment">//我们的配置文件可以直接放在类路径下叫messages.properties;</span></span><br></pre></td></tr></table></figure>
<p>3）去页面获取国际化的值；</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;Content-Type&quot;</span> <span class="attr">content</span>=<span class="string">&quot;text/html; charset=UTF-8&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1, shrink-to-fit=no&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;description&quot;</span> <span class="attr">content</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;author&quot;</span> <span class="attr">content</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">title</span>&gt;</span>Signin Template for Bootstrap<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">		<span class="comment">&lt;!-- Bootstrap core CSS --&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">&quot;asserts/css/bootstrap.min.css&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/webjars/bootstrap/4.4.1/css/bootstrap.min.css&#125;&quot;</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span>&gt;</span></span><br><span class="line">		<span class="comment">&lt;!-- Custom styles for this template --&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">&quot;asserts/css/signin.css&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/asserts/css/signin.css&#125;&quot;</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">	<span class="tag">&lt;<span class="name">body</span> <span class="attr">class</span>=<span class="string">&quot;text-center&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">form</span> <span class="attr">class</span>=<span class="string">&quot;form-signin&quot;</span> <span class="attr">action</span>=<span class="string">&quot;dashboard.html&quot;</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">img</span> <span class="attr">class</span>=<span class="string">&quot;mb-4&quot;</span> <span class="attr">src</span>=<span class="string">&quot;asserts/img/bootstrap-solid.svg&quot;</span> <span class="attr">th:src</span>=<span class="string">&quot;@&#123;/asserts/img/bootstrap-solid.svg&#125;&quot;</span>  <span class="attr">alt</span>=<span class="string">&quot;&quot;</span> <span class="attr">width</span>=<span class="string">&quot;72&quot;</span> <span class="attr">height</span>=<span class="string">&quot;72&quot;</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">h1</span> <span class="attr">class</span>=<span class="string">&quot;h3 mb-3 font-weight-normal&quot;</span> <span class="attr">th:text</span>=<span class="string">&quot;#&#123;login.tip&#125;&quot;</span>&gt;</span>Please sign in<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;sr-only&quot;</span>&gt;</span>Username<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;Username&quot;</span> <span class="attr">th:placeholder</span>=<span class="string">&quot;#&#123;login.username&#125;&quot;</span> <span class="attr">required</span>=<span class="string">&quot;&quot;</span> <span class="attr">autofocus</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;sr-only&quot;</span>&gt;</span>Password<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">th:placeholder</span>=<span class="string">&quot;#&#123;login.password&#125;&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;Password&quot;</span> <span class="attr">required</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;checkbox mb-3&quot;</span>&gt;</span></span><br><span class="line">				<span class="tag">&lt;<span class="name">label</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">value</span>=<span class="string">&quot;remember-me&quot;</span>/&gt;</span> [[#&#123;login.remember&#125;]]</span><br><span class="line">        <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-lg btn-primary btn-block&quot;</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">th:text</span>=<span class="string">&quot;#&#123;login.btn&#125;&quot;</span>&gt;</span>Sign in<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">&quot;mt-5 mb-3 text-muted&quot;</span>&gt;</span>© 2017-2018<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">a</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-sm&quot;</span>&gt;</span>中文<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">a</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-sm&quot;</span>&gt;</span>English<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"></span><br><span class="line">	<span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>效果：根据浏览器语言设置的信息切换了国际化</p>
<p>原理：</p>
<p>​		国际化 Locale（区域信息对象）、LocaleReslover（获取区域信息对象）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean</span></span><br><span class="line"><span class="meta">@ConditionalOnProperty(prefix = &quot;spring.mvc&quot;, name = &quot;locale&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> LocaleResolver <span class="title">localeResolver</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> FixedLocaleResolver(<span class="keyword">this</span>.mvcProperties.getLocale());</span><br><span class="line">    &#125;</span><br><span class="line">    AcceptHeaderLocaleResolver localeResolver = <span class="keyword">new</span> AcceptHeaderLocaleResolver();</span><br><span class="line">    localeResolver.setDefaultLocale(<span class="keyword">this</span>.mvcProperties.getLocale());</span><br><span class="line">    <span class="keyword">return</span> localeResolver;</span><br><span class="line">&#125;</span><br><span class="line">默认的就是根据请求头带来的区域信息获取Locater进行国际化</span><br></pre></td></tr></table></figure>
<p>4）点击链接切换国际化</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 可以在链接上携带区域信息</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyLocaleResolver</span> <span class="keyword">implements</span> <span class="title">LocaleResolver</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Locale <span class="title">resolveLocale</span><span class="params">(HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">        String l = request.getParameter(<span class="string">&quot;l&quot;</span>);</span><br><span class="line">        Locale locale = Locale.getDefault();</span><br><span class="line">        <span class="keyword">if</span> (!StringUtils.isEmpty(l)) &#123;</span><br><span class="line">            String[] split = l.split(<span class="string">&quot;_&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (split != <span class="keyword">null</span> &amp;&amp; split.length &gt; <span class="number">1</span>) &#123;</span><br><span class="line">                locale = <span class="keyword">new</span> Locale(split[<span class="number">0</span>], split[<span class="number">1</span>]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> locale;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setLocale</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Locale locale)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> LocaleResolver <span class="title">localeResolver</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> MyLocaleResolver();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="63-登录"><a class="markdownIt-Anchor" href="#63-登录">#</a> 6.3 登录</h3>
<p>开发期间模板引擎页面修改以后，要实时生效</p>
<p>1）禁用模板引擎的缓存 spring.thymeleaf.cache=false</p>
<p>2）页面修改完成以后重新编译 Ctrl + F9</p>
<p>登录错误消息的显示</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">style</span>=<span class="string">&quot;color: red&quot;</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;msg&#125;&quot;</span> <span class="attr">th:if</span>=<span class="string">&quot;$&#123;not #strings.isEmpty(msg)&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="64-拦截器进行登录检查"><a class="markdownIt-Anchor" href="#64-拦截器进行登录检查">#</a> 6.4 拦截器进行登录检查</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 登录检查</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginHandlerInterceptor</span> <span class="keyword">implements</span> <span class="title">HandlerInterceptor</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//目标方法执行前</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">preHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        Object user = request.getSession().getAttribute(<span class="string">&quot;loginUser&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (user == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="comment">//未登录，返回登录页面</span></span><br><span class="line">            request.setAttribute(<span class="string">&quot;msg&quot;</span>, <span class="string">&quot;没有权限，请先登录&quot;</span>);</span><br><span class="line">            request.getRequestDispatcher(<span class="string">&quot;/index.html&quot;</span>).forward(request, response);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//已登录，放行请求</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> WebMvcConfigurer <span class="title">webMvcConfigurer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    WebMvcConfigurer mvcConfigurer = <span class="keyword">new</span> WebMvcConfigurer() &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> </span>&#123;</span><br><span class="line">            registry.addViewController(<span class="string">&quot;/&quot;</span>).setViewName(<span class="string">&quot;login&quot;</span>);</span><br><span class="line">            registry.addViewController(<span class="string">&quot;/index.html&quot;</span>).setViewName(<span class="string">&quot;login&quot;</span>);</span><br><span class="line">            registry.addViewController(<span class="string">&quot;/main.html&quot;</span>).setViewName(<span class="string">&quot;dashboard&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//注册拦截器</span></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> </span>&#123;</span><br><span class="line">            registry.addInterceptor(<span class="keyword">new</span> LoginHandlerInterceptor()).addPathPatterns(<span class="string">&quot;/**&quot;</span>)</span><br><span class="line">                .excludePathPatterns(<span class="string">&quot;/&quot;</span>, <span class="string">&quot;/index.html&quot;</span>, <span class="string">&quot;/user/login&quot;</span>)</span><br><span class="line">                .excludePathPatterns(<span class="string">&quot;/webjars/**&quot;</span>, <span class="string">&quot;/asserts/**&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">return</span> mvcConfigurer;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="65-crud-员工列表"><a class="markdownIt-Anchor" href="#65-crud-员工列表">#</a> 6.5 CRUD - 员工列表</h3>
<p>实验要求：</p>
<p>1）RestfulCRUD：CRUD 满足 Rest 风格；</p>
<p>URI：/ 资源名称 / 资源标识      HTTP 请求方式区分对资源 CRUD 操作</p>
<table>
<thead>
<tr>
<th></th>
<th>普通 CRUD</th>
<th>RestfulCRUD</th>
</tr>
</thead>
<tbody>
<tr>
<td>查询</td>
<td>getEmp</td>
<td>emp — GET</td>
</tr>
<tr>
<td>添加</td>
<td>addEmp?xxx</td>
<td>emp — POST</td>
</tr>
<tr>
<td>修改</td>
<td>updateEmp?id=xxx&amp;xxx</td>
<td>emp/{id} — PUT</td>
</tr>
<tr>
<td>删除</td>
<td>deleteEmp?id=1</td>
<td>emp/{id} — DELETE</td>
</tr>
</tbody>
</table>
<p>2）实验请求架构</p>
<table>
<thead>
<tr>
<th></th>
<th>请求 URI</th>
<th>请求方式</th>
</tr>
</thead>
<tbody>
<tr>
<td>查询所有员工</td>
<td>emps</td>
<td>GET</td>
</tr>
<tr>
<td>查询某个员工</td>
<td id="">emp/</td>
<td>GET</td>
</tr>
<tr>
<td>添加页面</td>
<td>emp</td>
<td>GET</td>
</tr>
<tr>
<td>添加员工</td>
<td>emp</td>
<td>POST</td>
</tr>
<tr>
<td>来到修改页面（查出员工进行信息回显）</td>
<td id="">emp/</td>
<td>GET</td>
</tr>
<tr>
<td>修改员工</td>
<td id="">emp/</td>
<td>PUT</td>
</tr>
<tr>
<td>删除员工</td>
<td id="">emp/</td>
<td>DELETE</td>
</tr>
</tbody>
</table>
<p>3）员工列表</p>
<p>thymeleaf 公共页面元素抽取</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">1. 抽取公共片段</span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:fragment</span>=<span class="string">&quot;copy&quot;</span>&gt;</span></span><br><span class="line"><span class="symbol">&amp;copy;</span> 2011 The Good Thymes Virtual Grocery</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">2. 引入公共片段</span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:insert</span>=<span class="string">&quot;~&#123;footer :: copy&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">~&#123;templatename::selector&#125;：模板名::选择器</span><br><span class="line">~&#123;templatename::fragmentname&#125;：模板名::片段名</span><br><span class="line"></span><br><span class="line">3. 默认效果</span><br><span class="line">insert的功能片段在div标签中</span><br><span class="line">如果使用th:insert等属性引入，可以不写 ~&#123;&#125;；</span><br><span class="line">行内写法可以加上 [[~&#123;&#125;]];[(~&#123;&#125;)];</span><br></pre></td></tr></table></figure>
<p>三种引入功能片段的 th 属性：</p>
<p><strong>th:insert</strong>：将公共片段整个插入到声明的引用中</p>
<p><strong>th:replace</strong>：将引入元素替换为公共片段</p>
<p><strong>th:include</strong>：将被引入片段的内容包含进这个标签中</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">footer</span> <span class="attr">th:fragment</span>=<span class="string">&quot;copy&quot;</span>&gt;</span></span><br><span class="line"><span class="symbol">&amp;copy;</span> 2011 The Good Thymes Virtual Grocery</span><br><span class="line"><span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"></span><br><span class="line">引入方式</span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:insert</span>=<span class="string">&quot;footer :: copy&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:replace</span>=<span class="string">&quot;footer :: copy&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:include</span>=<span class="string">&quot;footer :: copy&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line">效果</span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line">    <span class="symbol">&amp;copy;</span> 2011 The Good Thymes Virtual Grocery</span><br><span class="line">    <span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span>   </span><br><span class="line"><span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="symbol">&amp;copy;</span> 2011 The Good Thymes Virtual Grocery</span><br><span class="line"><span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="symbol">&amp;copy;</span> 2011 The Good Thymes Virtual Grocery</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">&lt;/body</span><br></pre></td></tr></table></figure>
<p>引入片段的时候传入参数</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">nav</span> <span class="attr">class</span>=<span class="string">&quot;col-md-2 d-none d-md-block bg-light sidebar&quot;</span> <span class="attr">id</span>=<span class="string">&quot;sidebar&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;sidebar-sticky&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ul</span> <span class="attr">class</span>=<span class="string">&quot;nav flex-column&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">li</span> <span class="attr">class</span>=<span class="string">&quot;nav-item&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">a</span> <span class="attr">class</span>=<span class="string">&quot;nav-link active&quot;</span></span></span><br><span class="line"><span class="tag">                   <span class="attr">th:class</span>=<span class="string">&quot;$&#123;activeUri==&#x27;main.html&#x27;?&#x27;nav-link active&#x27;:&#x27;nav-link&#x27;&#125;&quot;</span></span></span><br><span class="line"><span class="tag">                   <span class="attr">href</span>=<span class="string">&quot;#&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/main.html&#125;&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">svg</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.w3.org/2000/svg&quot;</span> <span class="attr">width</span>=<span class="string">&quot;24&quot;</span> <span class="attr">height</span>=<span class="string">&quot;24&quot;</span> <span class="attr">viewBox</span>=<span class="string">&quot;0 0 24 24&quot;</span> <span class="attr">fill</span>=<span class="string">&quot;none&quot;</span> <span class="attr">stroke</span>=<span class="string">&quot;currentColor&quot;</span> <span class="attr">stroke-width</span>=<span class="string">&quot;2&quot;</span> <span class="attr">stroke-linecap</span>=<span class="string">&quot;round&quot;</span> <span class="attr">stroke-linejoin</span>=<span class="string">&quot;round&quot;</span> <span class="attr">class</span>=<span class="string">&quot;feather feather-home&quot;</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">path</span> <span class="attr">d</span>=<span class="string">&quot;M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">path</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">polyline</span> <span class="attr">points</span>=<span class="string">&quot;9 22 9 12 15 12 15 22&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">polyline</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">svg</span>&gt;</span></span><br><span class="line">                    Dashboard <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;sr-only&quot;</span>&gt;</span>(current)<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--引入侧边栏;传入参数--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">th:replace</span>=<span class="string">&quot;commons/bar::#sidebar(activeUri=&#x27;emps&#x27;)&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="66-crud-员工添加"><a class="markdownIt-Anchor" href="#66-crud-员工添加">#</a> 6.6 CRUD - 员工添加</h3>
<p>添加页面</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>LastName<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;zhangsan&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Email<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;email&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;zhangsan@atguigu.com&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Gender<span class="tag">&lt;/<span class="name">label</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-check form-check-inline&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">class</span>=<span class="string">&quot;form-check-input&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span>  <span class="attr">value</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;form-check-label&quot;</span>&gt;</span>男<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-check form-check-inline&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">class</span>=<span class="string">&quot;form-check-input&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span>  <span class="attr">value</span>=<span class="string">&quot;0&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;form-check-label&quot;</span>&gt;</span>女<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>department<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span>&gt;</span>1<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span>&gt;</span>2<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span>&gt;</span>3<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span>&gt;</span>4<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span>&gt;</span>5<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Birth<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;zhangsan&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-primary&quot;</span>&gt;</span>添加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>提交的数据格式不对：生日；日期</p>
<p>2020/1/1；2020-1-1；2020.1.1</p>
<p>日期格式化；SpringMVC 将页面提交的值需要转换为指定的类型；</p>
<p>2020.1.1—Date；类型转换，格式化；</p>
<p>默认日期是按照 / 的方式；</p>
<h3 id="67-crud-员工修改"><a class="markdownIt-Anchor" href="#67-crud-员工修改">#</a> 6.7 CRUD - 员工修改</h3>
<p>修改添加二合一表单</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--需要区分是员工修改还是添加；--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">th:action</span>=<span class="string">&quot;@&#123;/emp&#125;&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--发送put请求修改员工数据--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">1、SpringMVC中配置HiddenHttpMethodFilter;（SpringBoot自动配置好的）</span></span><br><span class="line"><span class="comment">2、页面创建一个post表单</span></span><br><span class="line"><span class="comment">3、创建一个input项，name=&quot;_method&quot;;值就是我们指定的请求方式</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;_method&quot;</span> <span class="attr">value</span>=<span class="string">&quot;put&quot;</span> <span class="attr">th:if</span>=<span class="string">&quot;$&#123;emp!=null&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;id&quot;</span> <span class="attr">th:if</span>=<span class="string">&quot;$&#123;emp!=null&#125;&quot;</span> <span class="attr">th:value</span>=<span class="string">&quot;$&#123;emp.id&#125;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>LastName<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;lastName&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;zhangsan&quot;</span> <span class="attr">th:value</span>=<span class="string">&quot;$&#123;emp!=null&#125;?$&#123;emp.lastName&#125;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Email<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;email&quot;</span> <span class="attr">type</span>=<span class="string">&quot;email&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;zhangsan@atguigu.com&quot;</span> <span class="attr">th:value</span>=<span class="string">&quot;$&#123;emp!=null&#125;?$&#123;emp.email&#125;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Gender<span class="tag">&lt;/<span class="name">label</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-check form-check-inline&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">class</span>=<span class="string">&quot;form-check-input&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1&quot;</span> <span class="attr">th:checked</span>=<span class="string">&quot;$&#123;emp!=null&#125;?$&#123;emp.gender==1&#125;&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;form-check-label&quot;</span>&gt;</span>男<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-check form-check-inline&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">class</span>=<span class="string">&quot;form-check-input&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;0&quot;</span> <span class="attr">th:checked</span>=<span class="string">&quot;$&#123;emp!=null&#125;?$&#123;emp.gender==0&#125;&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;form-check-label&quot;</span>&gt;</span>女<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>department<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--提交的是部门的id--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">name</span>=<span class="string">&quot;department.id&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">th:selected</span>=<span class="string">&quot;$&#123;emp!=null&#125;?$&#123;dept.id == emp.department.id&#125;&quot;</span> <span class="attr">th:value</span>=<span class="string">&quot;$&#123;dept.id&#125;&quot;</span> <span class="attr">th:each</span>=<span class="string">&quot;dept:$&#123;depts&#125;&quot;</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;dept.departmentName&#125;&quot;</span>&gt;</span>1<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span>&gt;</span>Birth<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;birth&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;zhangsan&quot;</span> <span class="attr">th:value</span>=<span class="string">&quot;$&#123;emp!=null&#125;?$&#123;#dates.format(emp.birth, &#x27;yyyy-MM-dd HH:mm&#x27;)&#125;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-primary&quot;</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;emp!=null&#125;?&#x27;修改&#x27;:&#x27;添加&#x27;&quot;</span>&gt;</span>添加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="68-crud-员工删除"><a class="markdownIt-Anchor" href="#68-crud-员工删除">#</a> 6.8 CRUD - 员工删除</h3>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">tr</span> <span class="attr">th:each</span>=<span class="string">&quot;emp:$&#123;emps&#125;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;emp.id&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span>&gt;</span>[[$&#123;emp.lastName&#125;]]<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;emp.email&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;emp.gender&#125;==0?&#x27;女&#x27;:&#x27;男&#x27;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;emp.department.departmentName&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;#dates.format(emp.birth, &#x27;yyyy-MM-dd HH:mm&#x27;)&#125;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-sm btn-primary&quot;</span> <span class="attr">th:href</span>=<span class="string">&quot;@&#123;/emp/&#125;+$&#123;emp.id&#125;&quot;</span>&gt;</span>编辑<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">button</span> <span class="attr">th:attr</span>=<span class="string">&quot;del_uri=@&#123;/emp/&#125;+$&#123;emp.id&#125;&quot;</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-sm btn-danger deleteBtn&quot;</span>&gt;</span>删除<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    $(<span class="string">&quot;.deleteBtn&quot;</span>).click(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">//删除当前员工的</span></span></span><br><span class="line"><span class="javascript">        $(<span class="string">&quot;#deleteEmpForm&quot;</span>).attr(<span class="string">&quot;action&quot;</span>,$(<span class="built_in">this</span>).attr(<span class="string">&quot;del_uri&quot;</span>)).submit();</span></span><br><span class="line"><span class="javascript">        <span class="keyword">return</span> <span class="literal">false</span>;</span></span><br><span class="line"><span class="javascript">    &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>高版本注意配置 spring.mvc.hiddenmethod.filter.enabled=true 属性</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">	<span class="meta">@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)</span></span><br><span class="line">	<span class="meta">@ConditionalOnProperty(prefix = &quot;spring.mvc.hiddenmethod.filter&quot;, name = &quot;enabled&quot;, matchIfMissing = false)</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> OrderedHiddenHttpMethodFilter <span class="title">hiddenHttpMethodFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">new</span> OrderedHiddenHttpMethodFilter();</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<h2 id="7-错误处理机制"><a class="markdownIt-Anchor" href="#7-错误处理机制">#</a> 7. 错误处理机制</h2>
<h3 id="71-springboot默认的错误处理机制"><a class="markdownIt-Anchor" href="#71-springboot默认的错误处理机制">#</a> 7.1 SpringBoot 默认的错误处理机制</h3>
<p>默认效果：</p>
<p>​		1）返回一个默认的错误页面</p>
<p><img data-src="SpringBoot/%E9%94%99%E8%AF%AF%E9%A1%B5%E9%9D%A2.png" alt=""></p>
<p>​		浏览器发送请求的请求头：</p>
<p><img data-src="SpringBoot/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8F%91%E8%AF%B7%E6%B1%82.png" alt=""></p>
<p>​		2）如果是其他客户端，默认响应一个 json 数据</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">&quot;timestamp&quot;</span>: <span class="string">&quot;2020-03-12T09:12:48.529+0000&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;status&quot;</span>: <span class="number">404</span>,</span><br><span class="line">    <span class="attr">&quot;error&quot;</span>: <span class="string">&quot;Not Found&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;message&quot;</span>: <span class="string">&quot;No message available&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;path&quot;</span>: <span class="string">&quot;/crud/a&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>​		<img data-src="SpringBoot/%E5%85%B6%E4%BB%96%E8%AF%B7%E6%B1%82.png" alt=""></p>
<p>原理：</p>
<p>​		可以参照 ErrorMvcAutoConfiguration；错误处理的自动配置；</p>
<p>​		给容器中添加了以下组件</p>
<p>​		1、DefaultErrorAttributes</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">帮我们在页面共享信息</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">getErrorAttributes</span><span class="params">(WebRequest webRequest, <span class="keyword">boolean</span> includeStackTrace)</span> </span>&#123;</span><br><span class="line">        Map&lt;String, Object&gt; errorAttributes = <span class="keyword">new</span> LinkedHashMap();</span><br><span class="line">        errorAttributes.put(<span class="string">&quot;timestamp&quot;</span>, <span class="keyword">new</span> Date());</span><br><span class="line">        <span class="keyword">this</span>.addStatus(errorAttributes, webRequest);</span><br><span class="line">        <span class="keyword">this</span>.addErrorDetails(errorAttributes, webRequest, includeStackTrace);</span><br><span class="line">        <span class="keyword">this</span>.addPath(errorAttributes, webRequest);</span><br><span class="line">        <span class="keyword">return</span> errorAttributes;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>​		2、BasicErrorController；处理默认的 /error 请求</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;$&#123;server.error.path:$&#123;error.path:/error&#125;&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BasicErrorController</span> <span class="keyword">extends</span> <span class="title">AbstractErrorControlle</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)</span> <span class="comment">//产生html的数据；浏览器请求</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> ModelAndView <span class="title">errorHtml</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> </span>&#123;</span><br><span class="line">		HttpStatus status = getStatus(request);</span><br><span class="line">		Map&lt;String, Object&gt; model = Collections</span><br><span class="line">				.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));</span><br><span class="line">		response.setStatus(status.value());</span><br><span class="line">        <span class="comment">//错误页面处理位置；包含页面地址和页面内容</span></span><br><span class="line">		ModelAndView modelAndView = resolveErrorView(request, response, status, model);</span><br><span class="line">		<span class="keyword">return</span> (modelAndView != <span class="keyword">null</span>) ? modelAndView : <span class="keyword">new</span> ModelAndView(<span class="string">&quot;error&quot;</span>, model);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@RequestMapping</span> <span class="comment">//产生json数据；其他客户端请求</span></span><br><span class="line">	<span class="keyword">public</span> ResponseEntity&lt;Map&lt;String, Object&gt;&gt; error(HttpServletRequest request) &#123;</span><br><span class="line">		HttpStatus status = getStatus(request);</span><br><span class="line">		<span class="keyword">if</span> (status == HttpStatus.NO_CONTENT) &#123;</span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;&gt;(status);</span><br><span class="line">		&#125;</span><br><span class="line">		Map&lt;String, Object&gt; body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;&gt;(body, status);</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>​		3、ErrorPageCustomizer</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Value(&quot;$&#123;error.path:/error&#125;&quot;)</span></span><br><span class="line">	<span class="keyword">private</span> String path = <span class="string">&quot;/error&quot;</span>; <span class="comment">//系统出现错误以后来到error请求进行处理；web.xml注册的错误页面规则</span></span><br></pre></td></tr></table></figure>
<p>​		4、DefaultErrorViewResolver</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> ModelAndView <span class="title">resolveErrorView</span><span class="params">(HttpServletRequest request, HttpStatus status, Map&lt;String, Object&gt; model)</span> </span>&#123;</span><br><span class="line">		ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);</span><br><span class="line">		<span class="keyword">if</span> (modelAndView == <span class="keyword">null</span> &amp;&amp; SERIES_VIEWS.containsKey(status.series())) &#123;</span><br><span class="line">			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> modelAndView;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> ModelAndView <span class="title">resolve</span><span class="params">(String viewName, Map&lt;String, Object&gt; model)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//默认springboot可以去找到一个页面；error/404</span></span><br><span class="line">		String errorViewName = <span class="string">&quot;error/&quot;</span> + viewName;</span><br><span class="line">        <span class="comment">//模板引擎可以解析这个页面地址就用模板引擎解析</span></span><br><span class="line">		TemplateAvailabilityProvider provider = <span class="keyword">this</span>.templateAvailabilityProviders.getProvider(errorViewName,</span><br><span class="line">				<span class="keyword">this</span>.applicationContext);</span><br><span class="line">		<span class="keyword">if</span> (provider != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="comment">//模板引擎可用的情况下返回到errorViewName指定的地址</span></span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">new</span> ModelAndView(errorViewName, model);</span><br><span class="line">		&#125;</span><br><span class="line">        <span class="comment">//模板引擎不可用，就在静态资源文件夹下找errorviewName对应的页面 error/404.html</span></span><br><span class="line">		<span class="keyword">return</span> resolveResource(errorViewName, model);</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>​		步骤：</p>
<p>​				一旦系统出现 4xx 或者 5xx 之类的错误；ErrorPageCustomizer 就会生效（定制错误的响应规则）；就会来到 /error 请求；就会被<strong> BasicErrorController</strong> 处理；</p>
<p>​				1）响应页面；去哪个页面是由<strong> DefaultErrorViewResolver</strong> 解析得到的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> ModelAndView <span class="title">resolveErrorView</span><span class="params">(HttpServletRequest request, HttpServletResponse response, HttpStatus status,</span></span></span><br><span class="line"><span class="params"><span class="function">			Map&lt;String, Object&gt; model)</span> </span>&#123;</span><br><span class="line">	<span class="comment">//所有的ErrorViewResolver得到ModelAndView</span></span><br><span class="line">    <span class="keyword">for</span> (ErrorViewResolver resolver : <span class="keyword">this</span>.errorViewResolvers) &#123;</span><br><span class="line">			ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);</span><br><span class="line">			<span class="keyword">if</span> (modelAndView != <span class="keyword">null</span>) &#123;</span><br><span class="line">				<span class="keyword">return</span> modelAndView;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<h3 id="72-如何定制错误响应"><a class="markdownIt-Anchor" href="#72-如何定制错误响应">#</a> 7.2 如何定制错误响应</h3>
<h4 id="721-如何定制错误的页面"><a class="markdownIt-Anchor" href="#721-如何定制错误的页面">#</a> 7.2.1 如何定制错误的页面；</h4>
<p>​		**1）有模板引擎的情况下；**error / 状态码；【将错误页面命名为 错误状态码.html 放在模板引擎文件里面的 error 文件夹下】，发生次状态码的错误就会来到 对应的页面；</p>
<p>​		我们可以使用 4xx 和 5xx 作为错误页面的文件名来匹配这种类型的所有错误，精确优先（优先寻找精确状态码的）；</p>
<p>​		页面信息能获取的信息：</p>
<p>​			timestamp：时间戳</p>
<p>​			status：状态码</p>
<p>​			error：错误提示</p>
<p>​			exception：异常对象</p>
<p>​			message：异常消息</p>
<p>​			errors：JSR303 数据校验的的错误</p>
<p>​			2）没有模板引擎（模板引擎下没有错误文件），静态资源文件夹下找</p>
<p>​			3）以上都没有，就是默认来到 springboot 默认的错误提示页面；</p>
<h4 id="722-如何定制错误的json数据"><a class="markdownIt-Anchor" href="#722-如何定制错误的json数据">#</a> 7.2.2 如何定制错误的 json 数据</h4>
<p>​		1）自定义异常处理 &amp; 返回 json 数据</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyExceptionHandler</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(UserNotExistException.class)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">handlerException</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Map&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;code&quot;</span>, <span class="string">&quot;user.not.exist&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> map;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//没有自适应效果</span></span><br></pre></td></tr></table></figure>
<p>​		2）转发到 /error 进行自适应响应效果处理</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ExceptionHandler(UserNotExistException.class)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">handlerException</span><span class="params">(ExceptionHandler e, HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//传入我们自己的错误状态码，否则就不会进入错误页面的解析</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Integer statusCode = (Integer) request.getAttribute(&quot;javax.servlet.error.status_code&quot;);</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        request.setAttribute(<span class="string">&quot;javax.servlet.error.status_code&quot;</span>, <span class="number">400</span>);</span><br><span class="line">        Map&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;code&quot;</span>, <span class="string">&quot;user.not.exist&quot;</span>);</span><br><span class="line">        <span class="comment">// 转发到/error</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;forward:/error&quot;</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>​		3）将我们的定制数据携带出去；</p>
<p>出现错误以后，会来到 /error 请求，会被 BasicErrorController 处理，响应出去可以获取的数据由 getErrorAttributes () 得到的（是 AbstractErrorController（ErrorController）规定的方法）；</p>
<p>​		1、完全来编写一个 ErrorController 的实现类【或者是编写 AbstractErrorController 的子类】，放到容器中；</p>
<p>​		2、页面上能用的数据，或者是 json 返回能用的数据都是通过 errorAttributes.getErrorAttributes 得到；</p>
<p>​				容器中 DefaultErrorAttributes.errorAttributes () 默认进行数据处理的；</p>
<p>自定义 ErrorAttributes：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//给容器中加入我们自己定义的ErrorAttributes</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyErrorAttributes</span> <span class="keyword">extends</span> <span class="title">DefaultErrorAttributes</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">getErrorAttributes</span><span class="params">(WebRequest webRequest, <span class="keyword">boolean</span> includeStackTrace)</span> </span>&#123;</span><br><span class="line">        Map&lt;String, Object&gt; map = <span class="keyword">super</span>.getErrorAttributes(webRequest, includeStackTrace);</span><br><span class="line">        map.put(<span class="string">&quot;user&quot;</span>,<span class="string">&quot;hyr&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.getErrorAttributes(webRequest, includeStackTrace);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>最终的效果：响应是自适应的，可以通过定制 ErrorAttributes 改变需要返回的内容。</p>
<h4 id="723-数据携带"><a class="markdownIt-Anchor" href="#723-数据携带">#</a> 7.2.3 数据携带</h4>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ExceptionHandler(UserNotExistException.class)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">handlerException</span><span class="params">(Exception e, HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//传入我们自己的错误状态码</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Integer statusCode = (Integer) request.getAttribute(&quot;javax.servlet.error.status_code&quot;);</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        request.setAttribute(<span class="string">&quot;javax.servlet.error.status_code&quot;</span>, <span class="number">400</span>);</span><br><span class="line">        Map&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;code&quot;</span>, <span class="string">&quot;user.not.exist&quot;</span>);</span><br><span class="line">        request.setAttribute(<span class="string">&quot;ext&quot;</span>, map);</span><br><span class="line">        <span class="comment">// 转发到/error</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;forward:/error&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">getErrorAttributes</span><span class="params">(WebRequest webRequest, <span class="keyword">boolean</span> includeStackTrace)</span> </span>&#123;</span><br><span class="line">        Map&lt;String, Object&gt; map = <span class="keyword">super</span>.getErrorAttributes(webRequest, includeStackTrace);</span><br><span class="line">        map.put(<span class="string">&quot;user&quot;</span>,<span class="string">&quot;hyr&quot;</span>);</span><br><span class="line">        <span class="comment">//我们异常处理器携带的数据</span></span><br><span class="line">        Map&lt;String, Object&gt; ext = (Map&lt;String, Object&gt;)webRequest.getAttribute(<span class="string">&quot;ext&quot;</span>, <span class="number">0</span>);</span><br><span class="line">        <span class="comment">//从request中取出错误处理器加入的数据</span></span><br><span class="line">        map.put(<span class="string">&quot;ext&quot;</span>, ext);</span><br><span class="line">        <span class="keyword">return</span> map;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h2 id="8-配置嵌入式servlet容器"><a class="markdownIt-Anchor" href="#8-配置嵌入式servlet容器">#</a> 8. 配置嵌入式 servlet 容器</h2>
<p>SpringBoot 默认是用的嵌入式 servlet 容器（Tomcat）;</p>
<p><img data-src="SpringBoot/tomcat%E4%BE%9D%E8%B5%96.png" alt=""></p>
<p>问题？</p>
<h3 id="81-如何定制和修改servlet容器的相关配置"><a class="markdownIt-Anchor" href="#81-如何定制和修改servlet容器的相关配置">#</a> 8.1 如何定制和修改 servlet 容器的相关配置；</h3>
<p>​		1、修改和 server 有关的配置（ServerProperties）；</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">server.port</span>=<span class="string">8081</span></span><br><span class="line"><span class="meta">server.servlet.context-path</span>=<span class="string">/crud</span></span><br><span class="line"><span class="meta">server.tomcat.uri-encoding</span>=<span class="string">UTF-8</span></span><br><span class="line"></span><br><span class="line"><span class="attr">//通用的servlet容器设置</span></span><br><span class="line"><span class="attr">server.xxx</span></span><br><span class="line"><span class="attr">//Tomcat设置</span></span><br><span class="line"><span class="attr">server.tomcat.xxx</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>​		2、编写一个 WebServerFactoryCustomizer：嵌入式的 Servlet 容器的定制器；来修改 Servlet 容器的配置；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> WebServerFactoryCustomizer&lt;ConfigurableWebServerFactory&gt; <span class="title">webServerFactoryWebServerFactoryCustomizer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> WebServerFactoryCustomizer&lt;ConfigurableWebServerFactory&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">customize</span><span class="params">(ConfigurableWebServerFactory factory)</span> </span>&#123;</span><br><span class="line">                factory.setPort(<span class="number">8083</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h3 id="82-注册servlet三大组件servlet-filter-listener"><a class="markdownIt-Anchor" href="#82-注册servlet三大组件servlet-filter-listener">#</a> 8.2 注册 Servlet 三大组件【Servlet、Filter、Listener】</h3>
<p>由于 SpringBoot 默认是以 jar 包的方式启动嵌入式的 Servlet 容器来启动 SpringBoot 的 web 应用，没有 web.xml 文件。</p>
<p>注册三大组件用以下方式：</p>
<p>ServletRegistrationBean：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//注册三大组件</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ServletRegistrationBean&lt;Servlet&gt; <span class="title">myServlet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ServletRegistrationBean&lt;Servlet&gt; registrationBean = <span class="keyword">new</span> ServletRegistrationBean&lt;Servlet&gt;(<span class="keyword">new</span> MyServlet(), <span class="string">&quot;/myServlet&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> registrationBean;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>FilterRegistrationBean：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> FilterRegistrationBean <span class="title">myFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        FilterRegistrationBean&lt;Filter&gt; registrationBean = <span class="keyword">new</span> FilterRegistrationBean&lt;&gt;();</span><br><span class="line">        registrationBean.setFilter(<span class="keyword">new</span> MyFilter());</span><br><span class="line">        registrationBean.setUrlPatterns(Arrays.asList(<span class="string">&quot;/hello&quot;</span>, <span class="string">&quot;/myServlet&quot;</span>));</span><br><span class="line">        <span class="keyword">return</span> registrationBean;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>ServletListenerRegistrationBean：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ServletListenerRegistrationBean <span class="title">myListener</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ServletListenerRegistrationBean&lt;MyListener&gt; registrationBean = <span class="keyword">new</span> ServletListenerRegistrationBean&lt;&gt;(<span class="keyword">new</span> MyListener());</span><br><span class="line">        <span class="keyword">return</span> registrationBean;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>SpringBoot 帮我们自动配置 SpringMVC 的时候，自动的注册 SpringMVC 的前段控制器；DispatcherServlet；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)</span></span><br><span class="line">		<span class="meta">@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)</span></span><br><span class="line">		<span class="function"><span class="keyword">public</span> DispatcherServletRegistrationBean <span class="title">dispatcherServletRegistration</span><span class="params">(DispatcherServlet dispatcherServlet,</span></span></span><br><span class="line"><span class="params"><span class="function">				WebMvcProperties webMvcProperties, ObjectProvider&lt;MultipartConfigElement&gt; multipartConfig)</span> </span>&#123;</span><br><span class="line">			DispatcherServletRegistrationBean registration = <span class="keyword">new</span> DispatcherServletRegistrationBean(dispatcherServlet,</span><br><span class="line">					webMvcProperties.getServlet().getPath());</span><br><span class="line">            <span class="comment">//默认拦截：/ 所有请求，包括静态资源，但是不拦截jsp； /* 会拦截jsp</span></span><br><span class="line">            <span class="comment">//可以通过spring.mvc.server.path来修改前端控制器默认拦截的请求路径</span></span><br><span class="line">			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);</span><br><span class="line">			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());</span><br><span class="line">			multipartConfig.ifAvailable(registration::setMultipartConfig);</span><br><span class="line">			<span class="keyword">return</span> registration;</span><br><span class="line">		&#125;</span><br></pre></td></tr></table></figure>
<h3 id="83-替换为其他嵌入式servlet容器"><a class="markdownIt-Anchor" href="#83-替换为其他嵌入式servlet容器">#</a> 8.3 替换为其他嵌入式 Servlet 容器</h3>
<p><img data-src="SpringBoot/%E5%86%85%E5%B5%8C%E5%BC%8F%E6%9C%8D%E5%8A%A1%E5%99%A8.png" alt=""></p>
<p>默认支持：</p>
<p>Tomcat（默认使用）</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>Jetty</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-tomcat<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-jetty<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>Undertow</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-tomcat<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-undertow<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>Netty</p>
<h3 id="84-嵌入式servlet容器自动配置原理"><a class="markdownIt-Anchor" href="#84-嵌入式servlet容器自动配置原理">#</a> 8.4 嵌入式 Servlet 容器自动配置原理</h3>
<p>EmbeddedWebServerFactoryCustomizerAutoConfiguration：嵌入式 servlet 容器自动配置</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(ServerProperties.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">EmbeddedWebServerFactoryCustomizerAutoConfiguration</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line">	<span class="meta">@ConditionalOnClass(&#123; Tomcat.class, UpgradeProtocol.class &#125;)</span><span class="comment">//判断当前是否引入了tomcatyilai </span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TomcatWebServerFactoryCustomizerConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="meta">@Bean</span></span><br><span class="line">		<span class="function"><span class="keyword">public</span> TomcatWebServerFactoryCustomizer <span class="title">tomcatWebServerFactoryCustomizer</span><span class="params">(Environment environment,</span></span></span><br><span class="line"><span class="params"><span class="function">				ServerProperties serverProperties)</span> </span>&#123;</span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">new</span> TomcatWebServerFactoryCustomizer(environment, serverProperties);</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<h3 id="85-嵌入式servlet容器启动原理"><a class="markdownIt-Anchor" href="#85-嵌入式servlet容器启动原理">#</a> 8.5 嵌入式 Servlet 容器启动原理</h3>
<p>什么时候创建嵌入式的 Servlet 容器工厂？什么时候获取嵌入式的 Servlet 容器并启动 Tomcat；</p>
<p>获取嵌入式的 Servlet 容器工厂：</p>
<p>1）SpringBoot 应用启动运行 run 方法</p>
<p>2）refreshContext (context);SpringBoot 刷新 IOC 容器【创建 IOC 容器对象，并初始化容器，创建容器中的每一个组件】；如果是 web 应用创建<strong> AnnotationConfigEmbeddedWebApplicationContext</strong>，否则：<strong>AnnotationConfigApplicationContext</strong></p>
<p>3）refresh(context);<strong> 刷新刚才创建好的 ioc 容器；</strong></p>
<p>4）onRefresh (); web 的 ioc 容器重写了 onRefresh 方法</p>
<p>5）webioc 容器会创建嵌入式的 Servlet 容器；<strong>createEmbeddedServletContainer</strong>();</p>
<p><strong>6）获取嵌入式的 Servlet 容器工厂：</strong></p>
<p>EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();</p>
<pre><code>从ioc容器中获取EmbeddedServletContainerFactory 组件；**TomcatEmbeddedServletContainerFactory**创建对象，后置处理器一看是这个对象，就获取所有的定制器来先定制Servlet容器的相关配置；
</code></pre>
<p>7）使用容器工厂获取嵌入式的 Servlet 容器 **：this.embeddedServletContainer = containerFactory      .getEmbeddedServletContainer (getSelfInitializer ());</p>
<p>8）嵌入式的 Servlet 容器创建对象并启动 Servlet 容器；</p>
<p><strong>先启动嵌入式的 Servlet 容器，再将 ioc 容器中剩下没有创建出的对象获取出来；</strong></p>
<p><strong><mark>IOC 容器启动创建嵌入式的 Servlet 容器</mark></strong></p>
<h2 id="9-使用外置的servlet容器"><a class="markdownIt-Anchor" href="#9-使用外置的servlet容器">#</a> 9. 使用外置的 servlet 容器</h2>
<p>嵌入式 Servlet 容器：jar</p>
<p>​		优点：简单，便携；</p>
<p>​		缺点：默认不支持 JSP、优化定制比较复杂（使用定制器【ServerProperties、自定义】，自己编写嵌入式 Servlet 容器的创建工厂）；</p>
<p>外置的 Servlet 容器：外面安装 Tomcat— 应用 war 包的方式打包；</p>
<h3 id="91-步骤"><a class="markdownIt-Anchor" href="#91-步骤">#</a> 9.1 步骤</h3>
<p>1）必须创建一个 war 项目；（利用 idea 创建好目录结构）</p>
<p>2）将嵌入式的 Tomcat 指定为 provided；</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-tomcat<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">scope</span>&gt;</span>provided<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>3）必须编写一个<strong> SpringBootServletInitializer</strong> 的子类，并调用 configure 方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServletInitializer</span> <span class="keyword">extends</span> <span class="title">SpringBootServletInitializer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="function"><span class="keyword">protected</span> SpringApplicationBuilder <span class="title">configure</span><span class="params">(SpringApplicationBuilder application)</span> </span>&#123;</span><br><span class="line">       <span class="comment">//传入SpringBoot应用的主程序</span></span><br><span class="line">      <span class="keyword">return</span> application.sources(SpringBoot04WebJspApplication.class);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>4）启动服务器就可以使用；</p>
<h3 id="92-原理"><a class="markdownIt-Anchor" href="#92-原理">#</a> 9.2 原理</h3>
<p>jar 包：执行 SpringBoot 主类的 main 方法，启动 ioc 容器，创建嵌入式的 Servlet 容器；</p>
<p>war 包：启动服务器，<strong>服务器启动 SpringBoot 应用</strong>【SpringBootServletInitializer】，启动 ioc 容器；</p>
<p>servlet3.0（Spring 注解版）：</p>
<p>8.2.4 Shared libraries / runtimes pluggability：</p>
<p>规则：<br>
1）服务器启动（web 应用启动）会创建当前 web 应用里面每一个 jar 包里面 ServletContainerInitializer 实例；</p>
<p>​		2）ServletContainerInitializer 的实现放在 jar 包的 META-INF/services 文件夹下，有一个名为 javax.servlet.ServletContainerInitializer 的文件，内容就是 ServletContainerInitializer 的实现类的全类名；</p>
<p>​		3）还可以使用 @HandlesTypes，在应用启动的时候加载我们感兴趣的类；</p>
<p>流程：</p>
<p>​		1）启动 Tomcat</p>
<p>​		2）org\springframework\spring-web\5.2.4.RELEASE\spring-web-5.2.4.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer：</p>
<p>Spring 的 web 模块里面有这个文件：<strong>org.springframework.web.SpringServletContainerInitializer</strong></p>
<p>​		3）SpringServletContainerInitializer 将 @HandlesTypes (WebApplicationInitializer.class) 标注的所有这个类型的类都传入到 onStartup 方法的 Set&lt;Class&lt;?&gt;&gt;；为这些 WebApplicationInitializer 类型的类创建实例；</p>
<p>​		4）每一个 WebApplicationInitializer 都调用自己的 onStartup；</p>
<p><img data-src="SpringBoot/WebApplicationInitializer%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0.png" alt=""></p>
<p>​		5）相当于我们的 SpringBootServletInitializer 的类会被创建对象，并执行 onStartup 方法；</p>
<p>​		6）SpringBootServletInitializer 实例执行 onStartup 的时候会 createRootApplicationContext；创建容器；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> WebApplicationContext <span class="title">createRootApplicationContext</span><span class="params">(ServletContext servletContext)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//1. 创建SpringApplicationBuilder</span></span><br><span class="line">    SpringApplicationBuilder builder = <span class="keyword">this</span>.createSpringApplicationBuilder();</span><br><span class="line">    builder.main(<span class="keyword">this</span>.getClass());</span><br><span class="line">    ApplicationContext parent = <span class="keyword">this</span>.getExistingRootWebApplicationContext(servletContext);</span><br><span class="line">    <span class="keyword">if</span> (parent != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.logger.info(<span class="string">&quot;Root context already created (using as parent).&quot;</span>);</span><br><span class="line">        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)<span class="keyword">null</span>);</span><br><span class="line">        builder.initializers(<span class="keyword">new</span> ApplicationContextInitializer[]&#123;<span class="keyword">new</span> ParentContextApplicationContextInitializer(parent)&#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    builder.initializers(<span class="keyword">new</span> ApplicationContextInitializer[]&#123;<span class="keyword">new</span> ServletContextApplicationContextInitializer(servletContext)&#125;);</span><br><span class="line">    builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);</span><br><span class="line">    <span class="comment">//2.调用configure，子类重写了这个方法，将springboot的主程序类传入进来</span></span><br><span class="line">    builder = <span class="keyword">this</span>.configure(builder);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//使用SpringBuilder创建一个spring应用</span></span><br><span class="line">    builder.listeners(<span class="keyword">new</span> ApplicationListener[]&#123;<span class="keyword">new</span> SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)&#125;);</span><br><span class="line">    SpringApplication application = builder.build();</span><br><span class="line">    <span class="keyword">if</span> (application.getAllSources().isEmpty() &amp;&amp; MergedAnnotations.from(<span class="keyword">this</span>.getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) &#123;</span><br><span class="line">        application.addPrimarySources(Collections.singleton(<span class="keyword">this</span>.getClass()));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Assert.state(!application.getAllSources().isEmpty(), <span class="string">&quot;No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.registerErrorPageFilter) &#123;</span><br><span class="line">        application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//启动spring应用</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.run(application);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>7）Spring 的应用就启动并且创建 IOC 容器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(String... args)</span> </span>&#123;</span><br><span class="line">    StopWatch stopWatch = <span class="keyword">new</span> StopWatch();</span><br><span class="line">    stopWatch.start();</span><br><span class="line">    ConfigurableApplicationContext context = <span class="keyword">null</span>;</span><br><span class="line">    Collection&lt;SpringBootExceptionReporter&gt; exceptionReporters = <span class="keyword">new</span> ArrayList();</span><br><span class="line">    <span class="keyword">this</span>.configureHeadlessProperty();</span><br><span class="line">    SpringApplicationRunListeners listeners = <span class="keyword">this</span>.getRunListeners(args);</span><br><span class="line">    listeners.starting();</span><br><span class="line"></span><br><span class="line">    Collection exceptionReporters;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        ApplicationArguments applicationArguments = <span class="keyword">new</span> DefaultApplicationArguments(args);</span><br><span class="line">        ConfigurableEnvironment environment = <span class="keyword">this</span>.prepareEnvironment(listeners, applicationArguments);</span><br><span class="line">        <span class="keyword">this</span>.configureIgnoreBeanInfo(environment);</span><br><span class="line">        Banner printedBanner = <span class="keyword">this</span>.printBanner(environment);</span><br><span class="line">        context = <span class="keyword">this</span>.createApplicationContext();</span><br><span class="line">        exceptionReporters = <span class="keyword">this</span>.getSpringFactoriesInstances(SpringBootExceptionReporter.class, <span class="keyword">new</span> Class[]&#123;ConfigurableApplicationContext.class&#125;, context);</span><br><span class="line">        <span class="keyword">this</span>.prepareContext(context, environment, listeners, applicationArguments, printedBanner);</span><br><span class="line">        <span class="comment">//刷新IOC容器</span></span><br><span class="line">        <span class="keyword">this</span>.refreshContext(context);</span><br><span class="line">        <span class="keyword">this</span>.afterRefresh(context, applicationArguments);</span><br><span class="line">        stopWatch.stop();</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.logStartupInfo) &#123;</span><br><span class="line">            (<span class="keyword">new</span> StartupInfoLogger(<span class="keyword">this</span>.mainApplicationClass)).logStarted(<span class="keyword">this</span>.getApplicationLog(), stopWatch);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        listeners.started(context);</span><br><span class="line">        <span class="keyword">this</span>.callRunners(context, applicationArguments);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var10) &#123;</span><br><span class="line">        <span class="keyword">this</span>.handleRunFailure(context, var10, exceptionReporters, listeners);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(var10);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        listeners.running(context);</span><br><span class="line">        <span class="keyword">return</span> context;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var9) &#123;</span><br><span class="line">        <span class="keyword">this</span>.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)<span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(var9);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong><mark>启动 Servlet 容器，再启动 SpringBoot 应用</mark></strong></p>
<h1 id="五-docker"><a class="markdownIt-Anchor" href="#五-docker">#</a> 五、Docker</h1>
<h2 id="51-简介"><a class="markdownIt-Anchor" href="#51-简介">#</a> 5.1 简介</h2>
<p><strong>Docker</strong> 是一个开源的应用容器引擎；是一个轻量级容器技术；</p>
<p>Docker 支持将软件编译成一个镜像；然后在镜像中各种软件做好配置，将镜像发布出去，其他使用者可以直接使用这个镜像；</p>
<p>运行中的这个镜像称为容器，容器启动是非常快速的。</p>
<p><img data-src="SpringBoot/docker.png" alt=""></p>
<p><img data-src="SpringBoot/docker2.png" alt=""></p>
<h2 id="52-核心概念"><a class="markdownIt-Anchor" href="#52-核心概念">#</a> 5.2 核心概念</h2>
<p>docker 主机 (Host)：安装了 Docker 程序的机器（Docker 直接安装在操作系统之上）；</p>
<p>docker 客户端 (Client)：连接 docker 主机进行操作；</p>
<p>docker 仓库 (Registry)：用来保存各种打包好的软件镜像；</p>
<p>docker 镜像 (Images)：软件打包好的镜像；放在 docker 仓库中；</p>
<p>docker 容器 (Container)：镜像启动后的实例称为一个容器；容器是独立运行的一个或一组应用</p>
<p>使用 Docker 的步骤：</p>
<p>1）安装 Docker；</p>
<p>2）去 Docker 仓库找到这个软件对应的镜像；</p>
<p>3）使用 Docker 运行这个镜像，这个镜像就会生成一个 Docker 容器；</p>
<p>4）对容器的启动停止就是对软件的启动停止；</p>
<h2 id="53-安装docker"><a class="markdownIt-Anchor" href="#53-安装docker">#</a> 5.3 安装 docker</h2>
<h3 id="531-安装linux虚拟机"><a class="markdownIt-Anchor" href="#531-安装linux虚拟机">#</a> 5.3.1 安装 Linux 虚拟机</h3>
<p>不介绍了；</p>
<h3 id="532-在linux上安装docker"><a class="markdownIt-Anchor" href="#532-在linux上安装docker">#</a> 5.3.2 在 Linux 上安装 docker</h3>
<p>步骤：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">1、检查内核版本，必须是3.10及以上</span><br><span class="line">uname -r</span><br><span class="line">2、安装docker</span><br><span class="line">yum install docker</span><br><span class="line">3、输入y确认安装</span><br><span class="line">4、启动docker</span><br><span class="line">[root@localhost ~]# systemctl start docker</span><br><span class="line">[root@localhost ~]# docker -v</span><br><span class="line">Docker version 1.12.6, build 3e8e77d/1.12.6</span><br><span class="line">5、开机启动docker</span><br><span class="line">[root@localhost ~]# systemctl enable docker</span><br><span class="line">Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.</span><br><span class="line">6、停止docker</span><br><span class="line">systemctl stop docker</span><br></pre></td></tr></table></figure>
<h3 id="533-启用国内镜像"><a class="markdownIt-Anchor" href="#533-启用国内镜像">#</a> 5.3.3 启用国内镜像</h3>
<p>1）编辑：/etc/docker/daemon.json</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;registry-mirrors&quot;</span>: [</span><br><span class="line">    <span class="string">&quot;https://docker.mirrors.ustc.edu.cn&quot;</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>2）重新启动 docker 服务</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">systemctl daemon-reload</span><br><span class="line">systemctl restart docker</span><br></pre></td></tr></table></figure>
<h2 id="54-docker常用命令操作"><a class="markdownIt-Anchor" href="#54-docker常用命令操作">#</a> 5.4  Docker 常用命令 &amp; 操作</h2>
<h3 id="541-镜像操作"><a class="markdownIt-Anchor" href="#541-镜像操作">#</a> 5.4.1 镜像操作</h3>
<table>
<thead>
<tr>
<th>操作</th>
<th>命令</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>检索</td>
<td>docker  search 关键字  eg：docker  search redis</td>
<td>我们经常去 docker  hub 上检索镜像的详细信息，如镜像的 TAG。</td>
</tr>
<tr>
<td>拉取</td>
<td>docker pull 镜像名:tag</td>
<td>:tag 是可选的，tag 表示标签，多为软件的版本，默认是 latest</td>
</tr>
<tr>
<td>列表</td>
<td>docker images</td>
<td>查看所有本地镜像</td>
</tr>
<tr>
<td>删除</td>
<td>docker rmi image-id</td>
<td>删除指定的本地镜像</td>
</tr>
</tbody>
</table>
<p><span class="exturl" data-url="aHR0cHM6Ly9odWIuZG9ja2VyLmNvbS8=">https://hub.docker.com/</span></p>
<h3 id="542-容器操作"><a class="markdownIt-Anchor" href="#542-容器操作">#</a> 5.4.2 容器操作</h3>
<p>软件镜像 ---- 运行镜像 ---- 产生一个容器；</p>
<p>步骤：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">1、搜索镜像</span><br><span class="line">[root@localhost ~]# docker search tomcat</span><br><span class="line">2、拉取镜像</span><br><span class="line">[root@localhost ~]# docker pull tomcat</span><br><span class="line">3、根据镜像启动容器</span><br><span class="line">docker run --name mytomcat -d tomcat:latest</span><br><span class="line">4、docker ps  </span><br><span class="line">查看运行中的容器</span><br><span class="line">5、 停止运行中的容器</span><br><span class="line">docker stop  容器的id</span><br><span class="line">6、查看所有的容器</span><br><span class="line">docker ps -a</span><br><span class="line">7、启动容器</span><br><span class="line">docker start 容器id</span><br><span class="line">8、删除一个容器</span><br><span class="line"> docker rm 容器id</span><br><span class="line">9、启动一个做了端口映射的tomcat</span><br><span class="line">[root@localhost ~]# docker run -d -p 8888:8080 tomcat</span><br><span class="line">-d：后台运行</span><br><span class="line">-p: 将主机的端口映射到容器的一个端口    主机端口:容器内部的端口</span><br><span class="line"></span><br><span class="line">10、为了演示简单关闭了linux的防火墙</span><br><span class="line">service firewalld status ；查看防火墙状态</span><br><span class="line">service firewalld stop：关闭防火墙</span><br><span class="line">11、查看容器的日志</span><br><span class="line">docker logs container-name/container-id</span><br><span class="line"></span><br><span class="line">更多命令参看</span><br><span class="line">https://docs.docker.com/engine/reference/commandline/docker/</span><br><span class="line">可以参考每一个镜像的文档</span><br></pre></td></tr></table></figure>
<h3 id="543-安装mysql示例"><a class="markdownIt-Anchor" href="#543-安装mysql示例">#</a> 5.4.3 安装 MySQL 示例</h3>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@VM_0_9_centos ~]# docker pull mysql</span><br></pre></td></tr></table></figure>
<p>错误的启动</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[root@VM_0_9_centos ~]# docker run --name mysql1 -d mysql</span><br><span class="line">c37ba254d14d1917dbac6743e2a40c61df9cd29ddabfdc7dc270665cdbade41c</span><br><span class="line"></span><br><span class="line">mysql退出了</span><br><span class="line">[root@VM_0_9_centos ~]# docker ps -a</span><br><span class="line">CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                          PORTS                    NAMES</span><br><span class="line">c37ba254d14d        mysql               &quot;docker-entrypoint...&quot;   About a minute ago   Exited (1) About a minute ago                            mysql1</span><br><span class="line">10ff331c3f42        tomcat              &quot;catalina.sh run&quot;        10 minutes ago       Up 10 minutes                   0.0.0.0:8888-&gt;8080/tcp   tomcat1</span><br><span class="line"></span><br><span class="line">//错误日志</span><br><span class="line">[root@VM_0_9_centos ~]# docker logs mysql1</span><br><span class="line">2020-03-17 06:24:59+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian10 started.</span><br><span class="line">2020-03-17 06:24:59+00:00 [Note] [Entrypoint]: Switching to dedicated user &#x27;mysql&#x27;</span><br><span class="line">2020-03-17 06:25:00+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian10 started.</span><br><span class="line">2020-03-17 06:25:00+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified</span><br><span class="line">        You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD；这个三个参数必须指定一个</span><br></pre></td></tr></table></figure>
<p>正确的启动</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@VM_0_9_centos ~]# docker run --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql</span><br><span class="line">b874c56bec49fb43024b3805ab51e9097da779f2f572c22c695305dedd684c5f</span><br><span class="line">[root@VM_0_9_centos ~]# docker ps</span><br><span class="line">CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES</span><br><span class="line">b874c56bec49        mysql               &quot;docker-entrypoint.sh&quot;   4 seconds ago       Up 3 seconds        3306/tcp            mysql01</span><br></pre></td></tr></table></figure>
<p>做了端口映射</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@VM_0_9_centos ~]# docker run -p 3306:3306 --name mysql02 -e MYSQL_ROOT_PASSWORD=123456 -d mysql</span><br><span class="line">ad10e4bc5c6a0f61cbad43898de71d366117d120e39db651844c0e73863b9434</span><br><span class="line">[root@VM_0_9_centos ~]# docker ps</span><br><span class="line">CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES</span><br><span class="line">ad10e4bc5c6a        mysql               &quot;docker-entrypoint.sh&quot;   4 seconds ago       Up 2 seconds        0.0.0.0:3306-&gt;3306/tcp   mysql02</span><br></pre></td></tr></table></figure>
<p>几个其他的高级操作</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">docker run --name mysql03 -v /conf/mysql:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag</span><br><span class="line">把主机的/conf/mysql文件夹挂载到 mysqldocker容器的/etc/mysql/conf.d文件夹里面</span><br><span class="line">改mysql的配置文件就只需要把mysql配置文件放在自定义的文件夹下（/conf/mysql）</span><br><span class="line"></span><br><span class="line">docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci</span><br><span class="line">指定mysql的一些配置参数</span><br></pre></td></tr></table></figure>
<p>切入 docker 命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it mysql1 bash</span><br></pre></td></tr></table></figure>
<h1 id="六-springboot与数据访问"><a class="markdownIt-Anchor" href="#六-springboot与数据访问">#</a> 六、SpringBoot 与数据访问</h1>
<h2 id="61-jdbc"><a class="markdownIt-Anchor" href="#61-jdbc">#</a> 6.1 JDBC</h2>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">datasource:</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">root</span></span><br><span class="line">    <span class="attr">password:</span> <span class="number">123456</span></span><br><span class="line">    <span class="attr">url:</span> <span class="string">jdbc:mysql://192.168.15.22:3306/jdbc</span></span><br><span class="line">    <span class="attr">driver-class-name:</span> <span class="string">com.mysql.jdbc.Driver</span></span><br></pre></td></tr></table></figure>
<p>效果：</p>
<p>​		默认是用 class com.zaxxer.hikari.HikariDataSource 作为数据源；</p>
<p>​		数据源的相关配置都在 DataSourceProperties 里面；</p>
<p>自动配置原理：</p>
<p>org.springframework.boot.autoconfigure.jdbc：</p>
<p>1、参考 DataSourceConfiguration，根据配置创建数据源，默认使用 hikari 连接池；可以使用 spring.datasource.type 指定自定义的数据源类型；</p>
<p>2、SpringBoot 默认可以支持；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">com.zaxxer.hikari.HikariDataSource</span><br><span class="line">org.apache.tomcat.jdbc.pool.DataSource</span><br><span class="line">org.apache.commons.dbcp2.BasicDataSource</span><br></pre></td></tr></table></figure>
<p>3、自定义数据源类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Generic DataSource configuration.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(DataSource.class)</span></span><br><span class="line"><span class="meta">@ConditionalOnProperty(name = &quot;spring.datasource.type&quot;)</span></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Generic</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="meta">@Bean</span></span><br><span class="line">   <span class="function">DataSource <span class="title">dataSource</span><span class="params">(DataSourceProperties properties)</span> </span>&#123;</span><br><span class="line">       <span class="comment">//使用DataSourceBuilder创建数据源，利用反射创建响应type的数据源，并且绑定相关属性</span></span><br><span class="line">       <span class="keyword">return</span> properties.initializeDataSourceBuilder().build();</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>4、<strong>DataSourceInitializer：ApplicationListener</strong>；</p>
<pre><code>作用：

	1）、runSchemaScripts();运行建表语句；

	2）、runDataScripts();运行插入数据的sql语句；
</code></pre>
<p>2.x 版本需添加配置</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">datasource:</span></span><br><span class="line">    <span class="attr">initialization-mode:</span> <span class="string">always</span></span><br></pre></td></tr></table></figure>
<p>默认只需要将文件命名为：</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">schema-*.sql、data-*.sql</span></span><br><span class="line"><span class="attr">默认规则：schema.sql，schema-all.sql；</span></span><br><span class="line"><span class="meta">可以使用</span>   <span class="string"></span></span><br><span class="line">	<span class="attr">schema</span>:<span class="string"></span></span><br><span class="line">      <span class="meta">-</span> <span class="string">classpath:department.sql</span></span><br><span class="line">      <span class="attr">指定位置</span></span><br></pre></td></tr></table></figure>
<p>5、操作数据库：自动配置了 JdbcTemplate 操作数据库</p>
<h2 id="62-整合druid数据源"><a class="markdownIt-Anchor" href="#62-整合druid数据源">#</a> 6.2 整合 Druid 数据源</h2>
<p>导入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/com.alibaba/druid --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>druid<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.20<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>配置文件</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">type:</span> <span class="string">com.alibaba.druid.pool.DruidDataSource</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#   数据源其他配置</span></span><br><span class="line">    <span class="attr">initialSize:</span> <span class="number">5</span></span><br><span class="line">    <span class="attr">minIdle:</span> <span class="number">5</span></span><br><span class="line">    <span class="attr">maxActive:</span> <span class="number">20</span></span><br><span class="line">    <span class="attr">maxWait:</span> <span class="number">60000</span></span><br><span class="line">    <span class="attr">timeBetweenEvictionRunsMillis:</span> <span class="number">60000</span></span><br><span class="line">    <span class="attr">minEvictableIdleTimeMillis:</span> <span class="number">300000</span></span><br><span class="line">    <span class="attr">validationQuery:</span> <span class="string">SELECT</span> <span class="number">1</span> <span class="string">FROM</span> <span class="string">DUAL</span></span><br><span class="line">    <span class="attr">testWhileIdle:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">testOnBorrow:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">testOnReturn:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">poolPreparedStatements:</span> <span class="literal">true</span></span><br><span class="line">    <span class="comment">#   配置监控统计拦截的filters，去掉后监控界面sql无法统计，&#x27;wall&#x27;用于防火墙</span></span><br><span class="line">    <span class="attr">filters:</span> <span class="string">stat,wall,log4j2</span></span><br><span class="line">    <span class="attr">maxPoolPreparedStatementPerConnectionSize:</span> <span class="number">20</span></span><br><span class="line">    <span class="attr">useGlobalDataSourceStat:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">connectionProperties:</span> <span class="string">druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500</span></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入Druid数据源</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DruidConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ConfigurationProperties(prefix = &quot;spring.datasource&quot;)</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> DruidDataSource <span class="title">druid</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> DruidDataSource();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//配置Druid的监控</span></span><br><span class="line">    <span class="comment">//1、配置一个管理后台的Servlet</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ServletRegistrationBean <span class="title">statServlet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ServletRegistrationBean&lt;StatViewServlet&gt; bean = <span class="keyword">new</span> ServletRegistrationBean&lt;&gt;(<span class="keyword">new</span> StatViewServlet(), <span class="string">&quot;/druid/*&quot;</span>);</span><br><span class="line">        Map&lt;String, String&gt; initParams = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        initParams.put(<span class="string">&quot;loginUsername&quot;</span>,<span class="string">&quot;admin&quot;</span>);</span><br><span class="line">        initParams.put(<span class="string">&quot;loginPassword&quot;</span>,<span class="string">&quot;123456&quot;</span>);</span><br><span class="line">        initParams.put(<span class="string">&quot;allow&quot;</span>,<span class="string">&quot;&quot;</span>);<span class="comment">//默认允许所有访问</span></span><br><span class="line">        initParams.put(<span class="string">&quot;deny&quot;</span>,<span class="string">&quot;&quot;</span>);</span><br><span class="line"></span><br><span class="line">        bean.setInitParameters(initParams);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> FilterRegistrationBean <span class="title">webStatFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        FilterRegistrationBean bean = <span class="keyword">new</span> FilterRegistrationBean();</span><br><span class="line">        bean.setFilter(<span class="keyword">new</span> WebStatFilter());</span><br><span class="line"></span><br><span class="line">        Map&lt;String,String&gt; initParams = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        initParams.put(<span class="string">&quot;exclusions&quot;</span>,<span class="string">&quot;*.js,*.css,/druid/*&quot;</span>);</span><br><span class="line"></span><br><span class="line">        bean.setInitParameters(initParams);</span><br><span class="line">        bean.setUrlPatterns(Arrays.asList(<span class="string">&quot;/*&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="63-整合mybatis"><a class="markdownIt-Anchor" href="#63-整合mybatis">#</a> 6.3 整合 MyBatis</h2>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.mybatis.spring.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mybatis-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img data-src="SpringBoot/mybatis%E4%BE%9D%E8%B5%96.png" alt=""></p>
<p>步骤：</p>
<p>1）配置数据源相关属性（见上一节 Druid）</p>
<p>2）给数据库建表</p>
<p>3）创建 JavaBean</p>
<h3 id="631-注解版"><a class="markdownIt-Anchor" href="#631-注解版">#</a> 6.3.1 注解版</h3>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//指定这是一个操作数据库的mapper</span></span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DepartmentMapper</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Select(&quot;select * from department where id = #&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function">Department <span class="title">getDeptById</span><span class="params">(Integer id)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Delete(&quot;delete form department where id = #&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">deleteDeptById</span><span class="params">(Integer id)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Options(useGeneratedKeys = true, keyProperty = &quot;id&quot;)</span></span><br><span class="line">    <span class="meta">@Insert(&quot;insert into department(department_name) values(#&#123;departmentName&#125;) &quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">insertDept</span><span class="params">(Department department)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Update(&quot;update department set department_name = #&#123;departmentName&#125; where id = #&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">updateDept</span><span class="params">(Department department)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>问题：</p>
<p>自定义 MyBatis 的配置规则；给容器中添加一个 ConfigurationCustomizer；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@org</span>.springframework.context.annotation.Configuration</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyBatisConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ConfigurationCustomizer <span class="title">configurationCustomizer</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ConfigurationCustomizer()&#123;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">customize</span><span class="params">(Configuration configuration)</span> </span>&#123;</span><br><span class="line">                configuration.setMapUnderscoreToCamelCase(<span class="keyword">true</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">使用MapperScan批量扫描所有的Mapper接口；</span><br><span class="line"><span class="meta">@MapperScan(value = &quot;com.study.springboot.mapper&quot;)</span></span><br><span class="line"><span class="meta">@org</span>.springframework.context.annotation.Configuration</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MybatisConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ConfigurationCustomizer <span class="title">configurationCustomizer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ConfigurationCustomizer()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">customize</span><span class="params">(Configuration configuration)</span> </span>&#123;</span><br><span class="line">                configuration.setMapUnderscoreToCamelCase(<span class="keyword">true</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="632-配置文件版"><a class="markdownIt-Anchor" href="#632-配置文件版">#</a> 6.3.2 配置文件版</h3>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mybatis:</span></span><br><span class="line">  <span class="attr">config-location:</span> <span class="string">classpath:mybatis/mybatis-config.xml</span> <span class="string">指定全局配置文件的位置</span></span><br><span class="line">  <span class="attr">mapper-locations:</span> <span class="string">classpath:mybatis/mapper/*.xml</span>  <span class="string">指定sql映射文件的位置</span></span><br></pre></td></tr></table></figure>
<p>更多使用参照</p>
<p><span class="exturl" data-url="aHR0cDovL3d3dy5teWJhdGlzLm9yZy9zcHJpbmctYm9vdC1zdGFydGVyL215YmF0aXMtc3ByaW5nLWJvb3QtYXV0b2NvbmZpZ3VyZS8=">http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/</span></p>
<h2 id="64-整合springdata-jpa"><a class="markdownIt-Anchor" href="#64-整合springdata-jpa">#</a> 6.4 整合 SpringData JPA</h2>
<h3 id="641-springdata简介"><a class="markdownIt-Anchor" href="#641-springdata简介">#</a> 6.4.1 SpringData 简介</h3>
<p><img data-src="SpringBoot/springdata.png" alt=""></p>
<h3 id="642-整合springdata-jpa"><a class="markdownIt-Anchor" href="#642-整合springdata-jpa">#</a> 6.4.2 整合 SpringData JPA</h3>
<p>JPA:ORM（Object Relational Mapping）；</p>
<p>1）编写一个实体类（bean）和数据表进行映射，并且配置好映射关系；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">/使用JPA注解配置映射关系</span><br><span class="line"><span class="meta">@Entity</span> <span class="comment">//告诉JPA这是一个实体类（和数据表映射的类）</span></span><br><span class="line"><span class="meta">@Table(name = &quot;tbl_user&quot;)</span> <span class="comment">//指定和那个数据表对应；如果省略默认表名为user;</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Id</span> <span class="comment">//这是一个主键</span></span><br><span class="line">    <span class="meta">@GeneratedValue(strategy = GenerationType.IDENTITY)</span> <span class="comment">//自增主键</span></span><br><span class="line">    <span class="keyword">private</span> Integer id;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Column(name = &quot;last_name&quot;, length = 50)</span> <span class="comment">//这是和数据表对应的一个列</span></span><br><span class="line">    <span class="keyword">private</span> String lastName;</span><br><span class="line">    <span class="meta">@Column</span> <span class="comment">//省略默认列名为属性名</span></span><br><span class="line">    <span class="keyword">private</span> String email;</span><br></pre></td></tr></table></figure>
<p>2）编写一个 Dao 接口来操作实体类对应的数据表（Repository）；</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//继承JpaRepository来完成对数据库的操作</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">UserRepository</span> <span class="keyword">extends</span> <span class="title">JpaRepository</span>&lt;<span class="title">User</span>, <span class="title">Integer</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>3）基本的配置 JpaProperties;</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">jpa:</span></span><br><span class="line">    <span class="attr">hibernate:</span></span><br><span class="line">      <span class="comment">#更新或者创建数据表</span></span><br><span class="line">      <span class="attr">ddl-auto:</span> <span class="string">update</span></span><br><span class="line">    <span class="comment">#控制台显示sql</span></span><br><span class="line">    <span class="attr">show-sql:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h1 id="七-启动配置原理"><a class="markdownIt-Anchor" href="#七-启动配置原理">#</a> 七、启动配置原理</h1>
<p>几个重要的事件回调机制</p>
<p>配置在 META-INF/spring.factories</p>
<p><strong>ApplicationContextInitializer</strong></p>
<p><strong>SpringApplicationRunListener</strong></p>
<p>只需要放在 ioc 容器中</p>
<p><strong>ApplicationRunner</strong></p>
<p><strong>CommandLineRunner</strong></p>
<p>启动流程：</p>
<h2 id="71-创建springapplication对象"><a class="markdownIt-Anchor" href="#71-创建springapplication对象">#</a> 7.1 创建 SpringApplication 对象</h2>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">SpringApplication</span><span class="params">(ResourceLoader resourceLoader, Class&lt;?&gt;... primarySources)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.sources = <span class="keyword">new</span> LinkedHashSet();</span><br><span class="line">    <span class="keyword">this</span>.bannerMode = Mode.CONSOLE;</span><br><span class="line">    <span class="keyword">this</span>.logStartupInfo = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">this</span>.addCommandLineProperties = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">this</span>.addConversionService = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">this</span>.headless = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">this</span>.registerShutdownHook = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">this</span>.additionalProfiles = <span class="keyword">new</span> HashSet();</span><br><span class="line">    <span class="keyword">this</span>.isCustomEnvironment = <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">this</span>.lazyInitialization = <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">this</span>.resourceLoader = resourceLoader;</span><br><span class="line">    Assert.notNull(primarySources, <span class="string">&quot;PrimarySources must not be null&quot;</span>);</span><br><span class="line">    <span class="comment">//保存主配置类</span></span><br><span class="line">    <span class="keyword">this</span>.primarySources = <span class="keyword">new</span> LinkedHashSet(Arrays.asList(primarySources));</span><br><span class="line">    <span class="comment">//判断web应用</span></span><br><span class="line">    <span class="keyword">this</span>.webApplicationType = WebApplicationType.deduceFromClasspath();</span><br><span class="line"><span class="comment">//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer，然后保存起来；</span></span><br><span class="line">  <span class="keyword">this</span>.setInitializers(<span class="keyword">this</span>.getSpringFactoriesInstances(ApplicationContextInitializer.class));</span><br><span class="line"><span class="comment">//从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener 		</span></span><br><span class="line">  <span class="keyword">this</span>.setListeners(<span class="keyword">this</span>.getSpringFactoriesInstances(ApplicationListener.class));</span><br><span class="line">    <span class="comment">//从多个配置类中找到有main方法的主配置类</span></span><br><span class="line">    <span class="keyword">this</span>.mainApplicationClass = <span class="keyword">this</span>.deduceMainApplicationClass();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img data-src="SpringBoot/ApplicationContextInitializer.png" alt=""></p>
<p><img data-src="SpringBoot/ApplicationListener.png" alt=""></p>
<h2 id="72-运行run方法"><a class="markdownIt-Anchor" href="#72-运行run方法">#</a> 7.2 运行 run 方法</h2>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(String... args)</span> </span>&#123;</span><br><span class="line">    StopWatch stopWatch = <span class="keyword">new</span> StopWatch();</span><br><span class="line">    stopWatch.start();</span><br><span class="line">    ConfigurableApplicationContext context = <span class="keyword">null</span>;</span><br><span class="line">    Collection&lt;SpringBootExceptionReporter&gt; exceptionReporters = <span class="keyword">new</span> ArrayList();</span><br><span class="line">    <span class="keyword">this</span>.configureHeadlessProperty();</span><br><span class="line">    <span class="comment">//获取SpringApplicationRunListeners；从类路径下META-INF/spring.factories</span></span><br><span class="line">    SpringApplicationRunListeners listeners = <span class="keyword">this</span>.getRunListeners(args);</span><br><span class="line">    <span class="comment">//回调所有的获取SpringApplicationRunListener.starting()方法</span></span><br><span class="line">    listeners.starting();</span><br><span class="line"></span><br><span class="line">    Collection exceptionReporters;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">//封装命令行参数</span></span><br><span class="line">        ApplicationArguments applicationArguments = <span class="keyword">new</span> DefaultApplicationArguments(args);</span><br><span class="line">        <span class="comment">//准备环境</span></span><br><span class="line">        ConfigurableEnvironment environment = <span class="keyword">this</span>.prepareEnvironment(listeners, applicationArguments);</span><br><span class="line">        <span class="comment">//创建环境完成后回调SpringApplicationRunListener.environmentPrepared()；表示环境准备完成</span></span><br><span class="line">        <span class="keyword">this</span>.configureIgnoreBeanInfo(environment);</span><br><span class="line">        Banner printedBanner = <span class="keyword">this</span>.printBanner(environment);</span><br><span class="line">        <span class="comment">//创建ApplicationContext；决定创建web的ioc,reactive的ioc还是普通的ioc</span></span><br><span class="line">        context = <span class="keyword">this</span>.createApplicationContext();</span><br><span class="line">        exceptionReporters = <span class="keyword">this</span>.getSpringFactoriesInstances(SpringBootExceptionReporter.class, <span class="keyword">new</span> Class[]&#123;ConfigurableApplicationContext.class&#125;, context);</span><br><span class="line">        <span class="comment">//准备上下文环境;将environment保存到ioc中；而且applyInitializers()；</span></span><br><span class="line">       <span class="comment">//applyInitializers()：回调之前保存的所有的ApplicationContextInitializer的initialize方法</span></span><br><span class="line">       <span class="comment">//回调所有的SpringApplicationRunListener的contextPrepared()；</span></span><br><span class="line">        <span class="keyword">this</span>.prepareContext(context, environment, listeners, applicationArguments, printedBanner);</span><br><span class="line">        <span class="comment">//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded()；</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">//s刷新容器；ioc容器初始化（如果是web应用还会创建嵌入式的Tomcat）；Spring注解版</span></span><br><span class="line">       <span class="comment">//扫描，创建，加载所有组件的地方；（配置类，组件，自动配置）</span></span><br><span class="line">        <span class="keyword">this</span>.refreshContext(context);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>.afterRefresh(context, applicationArguments);</span><br><span class="line">        stopWatch.stop();</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.logStartupInfo) &#123;</span><br><span class="line">            (<span class="keyword">new</span> StartupInfoLogger(<span class="keyword">this</span>.mainApplicationClass)).logStarted(<span class="keyword">this</span>.getApplicationLog(), stopWatch);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        listeners.started(context);</span><br><span class="line">        <span class="comment">//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调</span></span><br><span class="line">        <span class="comment">//ApplicationRunner先回调，CommandLineRunner再回调</span></span><br><span class="line">        <span class="keyword">this</span>.callRunners(context, applicationArguments);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var10) &#123;</span><br><span class="line">        <span class="keyword">this</span>.handleRunFailure(context, var10, exceptionReporters, listeners);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(var10);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        listeners.running(context);</span><br><span class="line">        <span class="comment">//整个SpringBoot应用启动完成以后返回启动的ioc容器；</span></span><br><span class="line">        <span class="keyword">return</span> context;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var9) &#123;</span><br><span class="line">        <span class="keyword">this</span>.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)<span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(var9);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="73-事件监听机制"><a class="markdownIt-Anchor" href="#73-事件监听机制">#</a> 7.3 事件监听机制</h2>
<p>配置在 META-INF/spring.factories</p>
<p><strong>ApplicationContextInitializer</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloApplicationContextInitializer</span> <span class="keyword">implements</span> <span class="title">ApplicationContextInitializer</span>&lt;<span class="title">ConfigurableApplicationContext</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initialize</span><span class="params">(ConfigurableApplicationContext configurableApplicationContext)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;ConfigurableApplicationContext...initialize... &quot;</span> + configurableApplicationContext);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>SpringApplicationRunListener</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloSpringApplicationRunListeners</span> <span class="keyword">implements</span> <span class="title">SpringApplicationRunListener</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HelloSpringApplicationRunListeners</span><span class="params">(SpringApplication application, String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">starting</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...starting...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">environmentPrepared</span><span class="params">(ConfigurableEnvironment environment)</span> </span>&#123;</span><br><span class="line">        Object o = environment.getSystemProperties().get(<span class="string">&quot;os.name&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...environmentPrepared... &quot;</span> + o);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">contextPrepared</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...contextPrepared...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">contextLoaded</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...contextLoaded...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">started</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...started...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">running</span><span class="params">(ConfigurableApplicationContext context)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...running...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">failed</span><span class="params">(ConfigurableApplicationContext context, Throwable exception)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;SpringApplicationRunListener...failed...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>配置（META-INF/spring.factories）</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Initializers</span></span><br><span class="line"><span class="meta">org.springframework.context.ApplicationContextInitializer</span>=<span class="string">\</span></span><br><span class="line"><span class="string">com.study.springboot.listener.HelloApplicationContextInitializer</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># SpringApplicationRunListener</span></span><br><span class="line"><span class="meta">org.springframework.boot.SpringApplicationRunListener</span>=<span class="string">\</span></span><br><span class="line"><span class="string">com.study.springboot.listener.HelloSpringApplicationRunListeners</span></span><br></pre></td></tr></table></figure>
<p>只需要放在 ioc 容器中</p>
<p><strong>ApplicationRunner</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloApplicationRunner</span> <span class="keyword">implements</span> <span class="title">ApplicationRunner</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">(ApplicationArguments args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;ApplicationRunner...run...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>CommandLineRunner</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloCommandLineRunner</span> <span class="keyword">implements</span> <span class="title">CommandLineRunner</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">(String... args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;CommandLineRunner...run... &quot;</span> + Arrays.asList(args));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="八-自定义starter"><a class="markdownIt-Anchor" href="#八-自定义starter">#</a> 八、自定义 starter</h1>
<p>starter：</p>
<p>​		1、这个场景需要使用到的依赖是什么？</p>
<p>​		2、如何编写自动配置？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span>  <span class="comment">//指定这个类是一个配置类</span></span><br><span class="line"><span class="meta">@ConditionalOnXXX</span>  <span class="comment">//在指定条件成立的情况下自动配置类生效</span></span><br><span class="line"><span class="meta">@AutoConfigureAfter</span>  <span class="comment">//指定自动配置类的顺序</span></span><br><span class="line"><span class="meta">@Bean</span>  <span class="comment">//给容器中添加组件</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@ConfigurationPropertie</span> <span class="comment">//结合相关xxxProperties类来绑定相关的配置</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties</span> <span class="comment">//让xxxProperties生效加入到容器中</span></span><br><span class="line"></span><br><span class="line">自动配置类要能加载</span><br><span class="line">将需要启动就加载的自动配置类，配置在META-INF/spring.factories</span><br><span class="line">org.springframework.boot.autoconfigure.EnableAutoConfiguration=\</span><br><span class="line">org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\</span><br></pre></td></tr></table></figure>
<p>​		3、模式：</p>
<p>​				启动器只用来做依赖导入；</p>
<p>​				专门来写一个自动配置模块；</p>
<p>​				启动器依赖自动配置；别人只需要引入启动器（starter）</p>
<p>​				mybatis-spring-boot-starter；自定义启动器名 - spring-boot-starter</p>
<p>步骤：</p>
<p>1）启动器模块</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.study.starter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>eutopia-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 启动器 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 引入自动配置模块 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.study.starter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>eutopia-spring-boot-starter-autoconfigurer<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2）自动配置模块</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">   <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.2.5.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">relativePath</span>/&gt;</span> <span class="comment">&lt;!-- lookup parent from repository --&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.study.starter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>eutopia-spring-boot-starter-autoconfigurer<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">name</span>&gt;</span>eutopia-spring-boot-starter-autoconfigurer<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">description</span>&gt;</span>Demo project for Spring Boot<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line"></span><br><span class="line">   <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!-- 引入spring-boot-starter：所有starter的基本配置 --&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;eutopia.hello&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloProperties</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String prefix;</span><br><span class="line">    <span class="keyword">private</span> String suffix;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getPrefix</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> prefix;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPrefix</span><span class="params">(String prefix)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.prefix = prefix;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getSuffix</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> suffix;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setSuffix</span><span class="params">(String suffix)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.suffix = suffix;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> HelloProperties helloProperties;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> HelloProperties <span class="title">getHelloProperties</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> helloProperties;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setHelloProperties</span><span class="params">(HelloProperties helloProperties)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.helloProperties = helloProperties;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHelloEutopia</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> helloProperties.getPrefix() + <span class="string">&quot;-&quot;</span> + name + <span class="string">&quot;-&quot;</span> + helloProperties.getSuffix();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(HelloProperties.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloServiceAutoConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    HelloProperties helloProperties;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> HelloService <span class="title">helloService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        HelloService helloService = <span class="keyword">new</span> HelloService();</span><br><span class="line">        helloService.setHelloProperties(helloProperties);</span><br><span class="line">        <span class="keyword">return</span> helloService;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>spring.factories</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Auto Configure</span><br><span class="line">org.springframework.boot.autoconfigure.EnableAutoConfiguration=\</span><br><span class="line">com.study.starter.HelloServiceAutoConfiguration</span><br></pre></td></tr></table></figure>
      <div class="tags">
          <a href="/blog/tags/SpringBoot/" rel="tag"><i class="ic i-tag"></i> SpringBoot</a>
      </div>
  </div>

   <footer>

    <div class="meta">
  <span class="item">
    <span class="icon">
      <i class="ic i-calendar-check"></i>
    </span>
    <span class="text">更新于</span>
    <time title="修改时间：2021-11-28 17:40:40" itemprop="dateModified" datetime="2021-11-28T17:40:40+08:00">2021-11-28</time>
  </span>
  <span id="2020/03/08/SpringBoot/" class="item leancloud_visitors" data-flag-title="SpringBoot 学习笔记 1" title="阅读次数">
      <span class="icon">
        <i class="ic i-eye"></i>
      </span>
      <span class="text">阅读次数</span>
      <span class="leancloud-visitors-count"></span>
      <span class="text">次</span>
  </span>
</div>

      
<div class="reward">
  <button><i class="ic i-heartbeat"></i> 赞赏</button>
  <p>请我喝[茶]~(￣▽￣)~*</p>
  <div id="qr">
      
      <div>
        <img data-src="/blog/images/wechatpay.png" alt="Rain Bear 微信支付">
        <p>微信支付</p>
      </div>
      
      <div>
        <img data-src="/blog/images/alipay.png" alt="Rain Bear 支付宝">
        <p>支付宝</p>
      </div>
      
      <div>
        <img data-src="/blog/images/paypal.png" alt="Rain Bear 贝宝">
        <p>贝宝</p>
      </div>
  </div>
</div>

      

<div id="copyright">
<ul>
  <li class="author">
    <strong>Rain Bear： </strong>Rain Bear <i class="ic i-at"><em>@</em></i>Endless
  </li>
  <li class="link">
    <strong>本文链接：</strong>
    <a href="http://fairy77.gitee.io/2020/03/08/SpringBoot/" title="SpringBoot 学习笔记 1">http://fairy77.gitee.io/2020/03/08/SpringBoot/</a>
  </li>
  <li class="license">
    <strong>版权声明： </strong>本站所有文章除特别声明外，均采用 <span class="exturl" data-url="aHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMC9kZWVkLnpo"><i class="ic i-creative-commons"><em>(CC)</em></i>BY-NC-SA</span> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

  </footer>

</article>

  </div>
  

<div class="post-nav">
    <div class="item left">
      

  <a href="/blog/2020/03/03/Nginx/" itemprop="url" rel="prev" data-background-image="https:&#x2F;&#x2F;tva1.sinaimg.cn&#x2F;mw690&#x2F;6833939bly1gipeu7txpzj20zk0m81kx.jpg" title="Nginx学习笔记">
  <span class="type">上一篇</span>
  <span class="category"><i class="ic i-flag"></i> </span>
  <h3>Nginx学习笔记</h3>
  </a>

    </div>
    <div class="item right">
      

  <a href="/blog/2020/03/19/%E6%95%B0%E7%BB%84%E7%9A%84%E4%BD%BF%E7%94%A8/" itemprop="url" rel="next" data-background-image="https:&#x2F;&#x2F;tva1.sinaimg.cn&#x2F;mw690&#x2F;6833939bly1giciuja1j1j20zk0m8kjl.jpg" title="数组的使用">
  <span class="type">下一篇</span>
  <span class="category"><i class="ic i-flag"></i> </span>
  <h3>数组的使用</h3>
  </a>

    </div>
</div>

  
  <div class="wrap" id="comments"></div>


        </div>
        <div id="sidebar">
          

<div class="inner">

  <div class="panels">
    <div class="inner">
      <div class="contents panel pjax" data-title="文章目录">
          <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%80-spring-boot%E5%85%A5%E9%97%A8"><span class="toc-number">1.</span> <span class="toc-text"> 一、Spring Boot 入门</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-spring-boot%E7%AE%80%E4%BB%8B"><span class="toc-number">1.1.</span> <span class="toc-text"> 1. Spring Boot 简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-%E5%BE%AE%E6%9C%8D%E5%8A%A1"><span class="toc-number">1.2.</span> <span class="toc-text"> 2. 微服务</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87"><span class="toc-number">1.3.</span> <span class="toc-text"> 3. 环境准备</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#31-maven%E8%AE%BE%E7%BD%AE"><span class="toc-number">1.3.1.</span> <span class="toc-text"> 3.1 MAVEN 设置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#32-idea%E8%AE%BE%E7%BD%AE"><span class="toc-number">1.3.2.</span> <span class="toc-text"> 3.2 IDEA 设置</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-spring-boot-helloworld"><span class="toc-number">1.4.</span> <span class="toc-text"> 4. Spring Boot HelloWorld</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#41-%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAmaven%E5%B7%A5%E7%A8%8Bjar"><span class="toc-number">1.4.1.</span> <span class="toc-text"> 4.1 创建一个 maven 工程；(jar)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#42-%E5%AF%BC%E5%85%A5springboot%E7%9B%B8%E5%85%B3%E4%BE%9D%E8%B5%96"><span class="toc-number">1.4.2.</span> <span class="toc-text"> 4.2 导入 springboot 相关依赖</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#43-%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%E4%B8%BB%E7%A8%8B%E5%BA%8F%E5%90%AF%E5%8A%A8spring-boot%E5%BA%94%E7%94%A8"><span class="toc-number">1.4.3.</span> <span class="toc-text"> 4.3 编写一个主程序，启动 Spring Boot 应用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#44-%E7%BC%96%E5%86%99%E7%9B%B8%E5%85%B3%E7%9A%84controller-service"><span class="toc-number">1.4.4.</span> <span class="toc-text"> 4.4 编写相关的 controller、service</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#45-%E8%BF%90%E8%A1%8C%E4%B8%BB%E7%A8%8B%E5%BA%8F%E6%B5%8B%E8%AF%95"><span class="toc-number">1.4.5.</span> <span class="toc-text"> 4.5 运行主程序测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#46-%E7%AE%80%E5%8C%96%E9%83%A8%E7%BD%B2"><span class="toc-number">1.4.6.</span> <span class="toc-text"> 4.6 简化部署</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-hello-world%E6%8E%A2%E7%A9%B6"><span class="toc-number">1.5.</span> <span class="toc-text"> 5. Hello World 探究</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#51-pom%E6%96%87%E4%BB%B6"><span class="toc-number">1.5.1.</span> <span class="toc-text"> 5.1 POM 文件</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#511-%E7%88%B6%E9%A1%B9%E7%9B%AE"><span class="toc-number">1.5.1.1.</span> <span class="toc-text"> 5.1.1 父项目</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#512-%E5%90%AF%E5%8A%A8%E5%99%A8"><span class="toc-number">1.5.1.2.</span> <span class="toc-text"> 5.1.2 启动器</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#52-%E4%B8%BB%E7%A8%8B%E5%BA%8F%E7%B1%BB%E4%B8%BB%E5%85%A5%E5%8F%A3%E7%B1%BB"><span class="toc-number">1.5.2.</span> <span class="toc-text"> 5.2 主程序类，主入口类</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-%E4%BD%BF%E7%94%A8spring-initializer%E5%BF%AB%E9%80%9F%E7%A9%BF%E5%BB%BAspring-boot%E9%A1%B9%E7%9B%AE"><span class="toc-number">1.6.</span> <span class="toc-text"> 6. 使用 Spring Initializer 快速穿建 Spring Boot 项目</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8C-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-number">2.</span> <span class="toc-text"> 二、配置文件</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-number">2.1.</span> <span class="toc-text"> 1. 配置文件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-yaml%E8%AF%AD%E6%B3%95"><span class="toc-number">2.2.</span> <span class="toc-text"> 2. YAML 语法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#21-%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95"><span class="toc-number">2.2.1.</span> <span class="toc-text"> 2.1 基本语法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-%E5%80%BC%E7%9A%84%E5%86%99%E6%B3%95"><span class="toc-number">2.2.2.</span> <span class="toc-text"> 2.2 值的写法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AD%97%E9%9D%A2%E9%87%8F%E6%99%AE%E9%80%9A%E7%9A%84%E5%80%BC%E6%95%B0%E5%AD%97%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%83%E5%B0%94"><span class="toc-number">2.2.2.1.</span> <span class="toc-text"> 字面量：普通的值（数字，字符串，布尔）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AF%B9%E8%B1%A1-map%E5%B1%9E%E6%80%A7%E5%92%8C%E5%80%BC%E9%94%AE%E5%80%BC%E5%AF%B9"><span class="toc-number">2.2.2.2.</span> <span class="toc-text"> 对象、Map (属性和值)（键值对）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%95%B0%E7%BB%84list-set"><span class="toc-number">2.2.2.3.</span> <span class="toc-text"> 数组（List、Set）</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%80%BC%E6%B3%A8%E5%85%A5"><span class="toc-number">2.3.</span> <span class="toc-text"> 3.  配置文件值注入</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#31-properties%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%9C%A8idea%E4%B8%AD%E9%BB%98%E8%AE%A4utf-8%E5%8F%AF%E8%83%BD%E4%BC%9A%E4%B9%B1%E7%A0%81"><span class="toc-number">2.3.1.</span> <span class="toc-text"> 3.1 properties 配置文件在 idea 中默认 utf-8 可能会乱码</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#32-value%E8%8E%B7%E5%8F%96%E5%80%BC%E5%92%8Cconfigurationproperties%E8%8E%B7%E5%8F%96%E5%80%BC%E6%AF%94%E8%BE%83"><span class="toc-number">2.3.2.</span> <span class="toc-text"> 3.2 @value 获取值和 @ConfigurationProperties 获取值比较</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#33-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E6%B3%A8%E5%85%A5%E5%80%BC%E6%95%B0%E6%8D%AE%E6%A0%A1%E9%AA%8C"><span class="toc-number">2.3.3.</span> <span class="toc-text"> 3.3 配置文件注入值数据校验</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#34-propertysourceimportresource"><span class="toc-number">2.3.4.</span> <span class="toc-text"> 3.4 @PropertySource&amp;@ImportResource</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%8D%A0%E4%BD%8D%E7%AC%A6"><span class="toc-number">2.4.</span> <span class="toc-text"> 4. 配置文件占位符</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#41-%E9%9A%8F%E6%9C%BA%E6%95%B0"><span class="toc-number">2.4.1.</span> <span class="toc-text"> 4.1 随机数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#42-%E5%8D%A0%E4%BD%8D%E7%AC%A6%E8%8E%B7%E5%8F%96%E4%B9%8B%E5%89%8D%E9%85%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%8C%87%E5%AE%9A%E9%BB%98%E8%AE%A4%E5%80%BC"><span class="toc-number">2.4.2.</span> <span class="toc-text"> 4.2 占位符获取之前配置的值，如果没有可以用：指定默认值</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-profile"><span class="toc-number">2.5.</span> <span class="toc-text"> 5. Profile</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#51-%E5%A4%9Aprofile%E6%96%87%E4%BB%B6"><span class="toc-number">2.5.1.</span> <span class="toc-text"> 5.1 多 profile 文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#52-yml%E6%94%AF%E6%8C%81%E5%A4%9A%E6%96%87%E6%A1%A3%E5%9D%97%E6%96%B9%E5%BC%8F"><span class="toc-number">2.5.2.</span> <span class="toc-text"> 5.2 yml 支持多文档块方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#53-%E6%BF%80%E6%B4%BB%E6%8C%87%E5%AE%9Aprofile"><span class="toc-number">2.5.3.</span> <span class="toc-text"> 5.3 激活指定 profile</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%8A%A0%E8%BD%BD%E4%BD%8D%E7%BD%AE"><span class="toc-number">2.6.</span> <span class="toc-text"> 6. 配置文件加载位置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-%E5%A4%96%E9%83%A8%E9%85%8D%E7%BD%AE%E5%8A%A0%E8%BD%BD%E9%A1%BA%E5%BA%8F"><span class="toc-number">2.7.</span> <span class="toc-text"> 7. 外部配置加载顺序</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="toc-number">2.8.</span> <span class="toc-text"> 8. 自动配置原理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#81-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="toc-number">2.8.1.</span> <span class="toc-text"> 8.1 自动配置原理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#82-%E7%BB%86%E8%8A%82"><span class="toc-number">2.8.2.</span> <span class="toc-text"> 8.2 细节</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#821-conditional%E6%B4%BE%E7%94%9F%E6%B3%A8%E8%A7%A3spring%E6%B3%A8%E8%A7%A3%E7%89%88%E5%8E%9F%E7%94%9F%E7%9A%84conditional%E4%BD%9C%E7%94%A8"><span class="toc-number">2.8.2.1.</span> <span class="toc-text"> 8.2.1 @Conditional 派生注解（Spring 注解版原生的 @Conditional 作用）</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%89-%E6%97%A5%E5%BF%97"><span class="toc-number">3.</span> <span class="toc-text"> 三、日志</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-%E6%97%A5%E5%BF%97%E6%A1%86%E6%9E%B6"><span class="toc-number">3.1.</span> <span class="toc-text"> 1. 日志框架</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-sel4j%E4%BD%BF%E7%94%A8"><span class="toc-number">3.2.</span> <span class="toc-text"> 2. SEL4j 使用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#21-%E5%A6%82%E4%BD%95%E5%9C%A8%E7%B3%BB%E7%BB%9F%E4%B8%AD%E4%BD%BF%E7%94%A8slf4j"><span class="toc-number">3.2.1.</span> <span class="toc-text"> 2.1 如何在系统中使用 SLF4j</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-%E9%81%97%E7%95%99%E9%97%AE%E9%A2%98"><span class="toc-number">3.2.2.</span> <span class="toc-text"> 2.2 遗留问题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#23-springboot%E6%97%A5%E5%BF%97%E5%85%B3%E7%B3%BB"><span class="toc-number">3.2.3.</span> <span class="toc-text"> 2.3 SpringBoot 日志关系</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#24-%E6%97%A5%E5%BF%97%E4%BD%BF%E7%94%A8"><span class="toc-number">3.2.4.</span> <span class="toc-text"> 2.4 日志使用</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#241-%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE"><span class="toc-number">3.2.4.1.</span> <span class="toc-text"> 2.4.1 默认配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#242-%E6%8C%87%E5%AE%9A%E9%85%8D%E7%BD%AE"><span class="toc-number">3.2.4.2.</span> <span class="toc-text"> 2.4.2 指定配置</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#25-%E6%97%A5%E5%BF%97%E6%A1%86%E6%9E%B6%E5%88%87%E6%8D%A2"><span class="toc-number">3.2.5.</span> <span class="toc-text"> 2.5 日志框架切换</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%9B%9B-web%E5%BC%80%E5%8F%91"><span class="toc-number">4.</span> <span class="toc-text"> 四、Web 开发</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-%E7%AE%80%E4%BB%8B"><span class="toc-number">4.1.</span> <span class="toc-text"> 1. 简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-springboot%E5%AF%B9%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E7%9A%84%E6%98%A0%E5%B0%84%E8%A7%84%E5%88%99"><span class="toc-number">4.2.</span> <span class="toc-text"> 2. SpringBoot 对静态资源的映射规则</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E"><span class="toc-number">4.3.</span> <span class="toc-text"> 3. 模板引擎</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#31-%E5%BC%95%E5%85%A5thymeleaf"><span class="toc-number">4.3.1.</span> <span class="toc-text"> 3.1 引入 Thymeleaf</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#32-thymeleaf%E4%BD%BF%E7%94%A8%E8%AF%AD%E6%B3%95"><span class="toc-number">4.3.2.</span> <span class="toc-text"> 3.2 Thymeleaf 使用 &amp; 语法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#33-%E8%AF%AD%E6%B3%95%E8%A7%84%E5%88%99"><span class="toc-number">4.3.3.</span> <span class="toc-text"> 3.3 语法规则</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-springmvc%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="toc-number">4.4.</span> <span class="toc-text"> 4. SpringMVC 自动配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#41-spring-mvc-auto-configuration"><span class="toc-number">4.4.1.</span> <span class="toc-text"> 4.1 Spring MVC Auto-configuration</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#42-%E6%89%A9%E5%B1%95springmvc"><span class="toc-number">4.4.2.</span> <span class="toc-text"> 4.2 扩展 SpringMVC</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#43-%E5%85%A8%E9%9D%A2%E6%8E%A5%E7%AE%A1springmvc"><span class="toc-number">4.4.3.</span> <span class="toc-text"> 4.3 全面接管 SpringMVC</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-%E5%A6%82%E4%BD%95%E4%BF%AE%E6%94%B9springboot%E7%9A%84%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE"><span class="toc-number">4.5.</span> <span class="toc-text"> 5. 如何修改 SpringBoot 的默认配置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-restfulcrud"><span class="toc-number">4.6.</span> <span class="toc-text"> 6. RestfulCRUD</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#61-%E9%BB%98%E8%AE%A4%E8%AE%BF%E9%97%AE%E9%A6%96%E9%A1%B5"><span class="toc-number">4.6.1.</span> <span class="toc-text"> 6.1 默认访问首页</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#62-%E5%9B%BD%E9%99%85%E5%8C%96"><span class="toc-number">4.6.2.</span> <span class="toc-text"> 6.2 国际化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#63-%E7%99%BB%E5%BD%95"><span class="toc-number">4.6.3.</span> <span class="toc-text"> 6.3 登录</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#64-%E6%8B%A6%E6%88%AA%E5%99%A8%E8%BF%9B%E8%A1%8C%E7%99%BB%E5%BD%95%E6%A3%80%E6%9F%A5"><span class="toc-number">4.6.4.</span> <span class="toc-text"> 6.4 拦截器进行登录检查</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#65-crud-%E5%91%98%E5%B7%A5%E5%88%97%E8%A1%A8"><span class="toc-number">4.6.5.</span> <span class="toc-text"> 6.5 CRUD - 员工列表</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#66-crud-%E5%91%98%E5%B7%A5%E6%B7%BB%E5%8A%A0"><span class="toc-number">4.6.6.</span> <span class="toc-text"> 6.6 CRUD - 员工添加</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#67-crud-%E5%91%98%E5%B7%A5%E4%BF%AE%E6%94%B9"><span class="toc-number">4.6.7.</span> <span class="toc-text"> 6.7 CRUD - 员工修改</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#68-crud-%E5%91%98%E5%B7%A5%E5%88%A0%E9%99%A4"><span class="toc-number">4.6.8.</span> <span class="toc-text"> 6.8 CRUD - 员工删除</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6"><span class="toc-number">4.7.</span> <span class="toc-text"> 7. 错误处理机制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#71-springboot%E9%BB%98%E8%AE%A4%E7%9A%84%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6"><span class="toc-number">4.7.1.</span> <span class="toc-text"> 7.1 SpringBoot 默认的错误处理机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#72-%E5%A6%82%E4%BD%95%E5%AE%9A%E5%88%B6%E9%94%99%E8%AF%AF%E5%93%8D%E5%BA%94"><span class="toc-number">4.7.2.</span> <span class="toc-text"> 7.2 如何定制错误响应</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#721-%E5%A6%82%E4%BD%95%E5%AE%9A%E5%88%B6%E9%94%99%E8%AF%AF%E7%9A%84%E9%A1%B5%E9%9D%A2"><span class="toc-number">4.7.2.1.</span> <span class="toc-text"> 7.2.1 如何定制错误的页面；</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#722-%E5%A6%82%E4%BD%95%E5%AE%9A%E5%88%B6%E9%94%99%E8%AF%AF%E7%9A%84json%E6%95%B0%E6%8D%AE"><span class="toc-number">4.7.2.2.</span> <span class="toc-text"> 7.2.2 如何定制错误的 json 数据</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#723-%E6%95%B0%E6%8D%AE%E6%90%BA%E5%B8%A6"><span class="toc-number">4.7.2.3.</span> <span class="toc-text"> 7.2.3 数据携带</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-%E9%85%8D%E7%BD%AE%E5%B5%8C%E5%85%A5%E5%BC%8Fservlet%E5%AE%B9%E5%99%A8"><span class="toc-number">4.8.</span> <span class="toc-text"> 8. 配置嵌入式 servlet 容器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#81-%E5%A6%82%E4%BD%95%E5%AE%9A%E5%88%B6%E5%92%8C%E4%BF%AE%E6%94%B9servlet%E5%AE%B9%E5%99%A8%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE"><span class="toc-number">4.8.1.</span> <span class="toc-text"> 8.1 如何定制和修改 servlet 容器的相关配置；</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#82-%E6%B3%A8%E5%86%8Cservlet%E4%B8%89%E5%A4%A7%E7%BB%84%E4%BB%B6servlet-filter-listener"><span class="toc-number">4.8.2.</span> <span class="toc-text"> 8.2 注册 Servlet 三大组件【Servlet、Filter、Listener】</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#83-%E6%9B%BF%E6%8D%A2%E4%B8%BA%E5%85%B6%E4%BB%96%E5%B5%8C%E5%85%A5%E5%BC%8Fservlet%E5%AE%B9%E5%99%A8"><span class="toc-number">4.8.3.</span> <span class="toc-text"> 8.3 替换为其他嵌入式 Servlet 容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#84-%E5%B5%8C%E5%85%A5%E5%BC%8Fservlet%E5%AE%B9%E5%99%A8%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="toc-number">4.8.4.</span> <span class="toc-text"> 8.4 嵌入式 Servlet 容器自动配置原理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#85-%E5%B5%8C%E5%85%A5%E5%BC%8Fservlet%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%8E%9F%E7%90%86"><span class="toc-number">4.8.5.</span> <span class="toc-text"> 8.5 嵌入式 Servlet 容器启动原理</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-%E4%BD%BF%E7%94%A8%E5%A4%96%E7%BD%AE%E7%9A%84servlet%E5%AE%B9%E5%99%A8"><span class="toc-number">4.9.</span> <span class="toc-text"> 9. 使用外置的 servlet 容器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#91-%E6%AD%A5%E9%AA%A4"><span class="toc-number">4.9.1.</span> <span class="toc-text"> 9.1 步骤</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#92-%E5%8E%9F%E7%90%86"><span class="toc-number">4.9.2.</span> <span class="toc-text"> 9.2 原理</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%94-docker"><span class="toc-number">5.</span> <span class="toc-text"> 五、Docker</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#51-%E7%AE%80%E4%BB%8B"><span class="toc-number">5.1.</span> <span class="toc-text"> 5.1 简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#52-%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5"><span class="toc-number">5.2.</span> <span class="toc-text"> 5.2 核心概念</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#53-%E5%AE%89%E8%A3%85docker"><span class="toc-number">5.3.</span> <span class="toc-text"> 5.3 安装 docker</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#531-%E5%AE%89%E8%A3%85linux%E8%99%9A%E6%8B%9F%E6%9C%BA"><span class="toc-number">5.3.1.</span> <span class="toc-text"> 5.3.1 安装 Linux 虚拟机</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#532-%E5%9C%A8linux%E4%B8%8A%E5%AE%89%E8%A3%85docker"><span class="toc-number">5.3.2.</span> <span class="toc-text"> 5.3.2 在 Linux 上安装 docker</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#533-%E5%90%AF%E7%94%A8%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F"><span class="toc-number">5.3.3.</span> <span class="toc-text"> 5.3.3 启用国内镜像</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#54-docker%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%93%8D%E4%BD%9C"><span class="toc-number">5.4.</span> <span class="toc-text"> 5.4  Docker 常用命令 &amp; 操作</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#541-%E9%95%9C%E5%83%8F%E6%93%8D%E4%BD%9C"><span class="toc-number">5.4.1.</span> <span class="toc-text"> 5.4.1 镜像操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#542-%E5%AE%B9%E5%99%A8%E6%93%8D%E4%BD%9C"><span class="toc-number">5.4.2.</span> <span class="toc-text"> 5.4.2 容器操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#543-%E5%AE%89%E8%A3%85mysql%E7%A4%BA%E4%BE%8B"><span class="toc-number">5.4.3.</span> <span class="toc-text"> 5.4.3 安装 MySQL 示例</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AD-springboot%E4%B8%8E%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE"><span class="toc-number">6.</span> <span class="toc-text"> 六、SpringBoot 与数据访问</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#61-jdbc"><span class="toc-number">6.1.</span> <span class="toc-text"> 6.1 JDBC</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#62-%E6%95%B4%E5%90%88druid%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="toc-number">6.2.</span> <span class="toc-text"> 6.2 整合 Druid 数据源</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#63-%E6%95%B4%E5%90%88mybatis"><span class="toc-number">6.3.</span> <span class="toc-text"> 6.3 整合 MyBatis</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#631-%E6%B3%A8%E8%A7%A3%E7%89%88"><span class="toc-number">6.3.1.</span> <span class="toc-text"> 6.3.1 注解版</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#632-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%89%88"><span class="toc-number">6.3.2.</span> <span class="toc-text"> 6.3.2 配置文件版</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#64-%E6%95%B4%E5%90%88springdata-jpa"><span class="toc-number">6.4.</span> <span class="toc-text"> 6.4 整合 SpringData JPA</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#641-springdata%E7%AE%80%E4%BB%8B"><span class="toc-number">6.4.1.</span> <span class="toc-text"> 6.4.1 SpringData 简介</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#642-%E6%95%B4%E5%90%88springdata-jpa"><span class="toc-number">6.4.2.</span> <span class="toc-text"> 6.4.2 整合 SpringData JPA</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%83-%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="toc-number">7.</span> <span class="toc-text"> 七、启动配置原理</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#71-%E5%88%9B%E5%BB%BAspringapplication%E5%AF%B9%E8%B1%A1"><span class="toc-number">7.1.</span> <span class="toc-text"> 7.1 创建 SpringApplication 对象</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#72-%E8%BF%90%E8%A1%8Crun%E6%96%B9%E6%B3%95"><span class="toc-number">7.2.</span> <span class="toc-text"> 7.2 运行 run 方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#73-%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E6%9C%BA%E5%88%B6"><span class="toc-number">7.3.</span> <span class="toc-text"> 7.3 事件监听机制</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AB-%E8%87%AA%E5%AE%9A%E4%B9%89starter"><span class="toc-number">8.</span> <span class="toc-text"> 八、自定义 starter</span></a></li></ol>
      </div>
      <div class="related panel pjax" data-title="系列文章">
      </div>
      <div class="overview panel" data-title="站点概览">
        <div class="author" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <img class="image" itemprop="image" alt="Rain Bear"
      data-src="/blog/images/avatar.jpg">
  <p class="name" itemprop="name">Rain Bear</p>
  <div class="description" itemprop="description"></div>
</div>

<nav class="state">
    <div class="item posts">
      <a href="/blog/archives/">
        <span class="count">11</span>
        <span class="name">文章</span>
      </a>
    </div>
    <div class="item tags">
      <a href="/blog/tags/">
        <span class="count">8</span>
        <span class="name">标签</span>
      </a>
    </div>
</nav>

<div class="social">
      <span class="exturl item github" data-url="aHR0cHM6Ly9naXRodWIuY29tL2ZhaXJ5Nw==" title="https:&#x2F;&#x2F;github.com&#x2F;fairy7"><i class="ic i-github"></i></span>
      <span class="exturl item zhihu" data-url="aHR0cHM6Ly9naXRlZS5jb20vZmFpcnk3Nw==" title="https:&#x2F;&#x2F;gitee.com&#x2F;fairy77"><i class="ic i-gitee"></i></span>
      <span class="exturl item music" data-url="aHR0cHM6Ly9tdXNpYy4xNjMuY29tLyMvdXNlci9ob21lP2lkPTI1Njk2NTkxNg==" title="https:&#x2F;&#x2F;music.163.com&#x2F;#&#x2F;user&#x2F;home?id&#x3D;256965916"><i class="ic i-cloud-music"></i></span>
</div>

<ul class="menu">
  
    
  <li class="item">
    <a href="/blog/" rel="section"><i class="ic i-home"></i>首页</a>
  </li>

    
  <li class="item">
    <a href="/blog/about/" rel="section"><i class="ic i-user"></i>关于</a>
  </li>

        
  <li class="item dropdown">
      <a href="javascript:void(0);"><i class="ic i-feather"></i>文章</a>
    <ul class="submenu">

        
  <li class="item">
    <a href="/blog/archives/" rel="section"><i class="ic i-list-alt"></i>归档</a>
  </li>

        
  <li class="item">
    <a href="/blog/categories/" rel="section"><i class="ic i-th"></i>分类</a>
  </li>

        
  <li class="item">
    <a href="/blog/tags/" rel="section"><i class="ic i-tags"></i>标签</a>
  </li>

  </ul>
    
  <li class="item">
    <a href="/blog/friends/" rel="section"><i class="ic i-heart"></i>friends</a>
  </li>

    
  <li class="item">
    <a href="/blog/links/" rel="section"><i class="ic i-magic"></i>links</a>
  </li>


</ul>

      </div>
    </div>
  </div>

  <ul id="quick">
    <li class="prev pjax">
        <a href="/blog/2020/03/03/Nginx/" rel="prev" title="上一篇"><i class="ic i-chevron-left"></i></a>
    </li>
    <li class="up"><i class="ic i-arrow-up"></i></li>
    <li class="down"><i class="ic i-arrow-down"></i></li>
    <li class="next pjax">
        <a href="/blog/2020/03/19/%E6%95%B0%E7%BB%84%E7%9A%84%E4%BD%BF%E7%94%A8/" rel="next" title="下一篇"><i class="ic i-chevron-right"></i></a>
    </li>
    <li class="percent"></li>
  </ul>
</div>


        </div>
        <div class="dimmer"></div>
      </div>
    </main>
    <footer id="footer">
      <div class="inner">
        <div class="widgets">
          
<div class="rpost pjax">
  <h2>随机文章</h2>
  <ul>
      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/03/03/Nginx/" title="Nginx学习笔记">Nginx学习笔记</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/03/20/MySQL%E7%B4%A2%E5%BC%95%E5%8E%9F%E7%90%86/" title="MySQL索引原理">MySQL索引原理</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/03/01/%E9%85%8D%E7%BD%AELinux%E8%99%9A%E6%8B%9F%E6%9C%BA/" title="配置Linux虚拟机">配置Linux虚拟机</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/02/29/MySQL%E5%AE%89%E8%A3%85/" title="MySQL安装">MySQL安装</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/03/19/%E6%95%B0%E7%BB%84%E7%9A%84%E4%BD%BF%E7%94%A8/" title="数组的使用">数组的使用</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2021/11/19/tomcat/" title="tomcat">tomcat</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/02/28/String%E5%92%8CStringBuffer%E3%80%81StringBuilder%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9F/" title="String和StringBuffer、StringBuilder的区别？">String和StringBuffer、StringBuilder的区别？</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/02/28/%E8%8E%B7%E5%8F%96%E7%94%A8%E9%94%AE%E7%9B%98%E8%BE%93%E5%85%A5%E5%B8%B8%E7%94%A8%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%B3%95/" title="获取用键盘输入常用的两种方法">获取用键盘输入常用的两种方法</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/03/01/linux-basic-operation/" title="Linux基本操作">Linux基本操作</a></span>
  </li>

      
  <li class="item">
    
<div class="breadcrumb">
</div>

    <span><a href="/blog/2020/02/29/git-operation/" title="Git&amp;Github">Git&Github</a></span>
  </li>

  </ul>
</div>
<div>
  <h2>最新评论</h2>
  <ul class="leancloud-recent-comment"></ul>
</div>

        </div>
        <div class="status">
  <div class="copyright">
    
    &copy; 2019 – 
    <span itemprop="copyrightYear">2021</span>
    <span class="with-love">
      <i class="ic i-sakura rotate"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">Rain Bear @ 夏季大三角</span>
  </div>
  <div class="count">
    <span class="post-meta-item-icon">
      <i class="ic i-chart-area"></i>
    </span>
    <span title="站点总字数">106k 字</span>

    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="ic i-coffee"></i>
    </span>
    <span title="站点阅读时长">1:36</span>
  </div>
  <div class="powered-by">
    基于 <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlv">Hexo</span> & Theme.<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FtZWhpbWUvaGV4by10aGVtZS1zaG9rYQ==">Shoka</span>
  </div>
</div>

      </div>
    </footer>
  </div>
<script data-config type="text/javascript">
  var LOCAL = {
    path: '2020/03/08/SpringBoot/',
    favicon: {
      show: "（●´3｀●）やれやれだぜ",
      hide: "(´Д｀)大変だ！"
    },
    search : {
      placeholder: "文章搜索",
      empty: "关于 「 ${query} 」，什么也没搜到",
      stats: "${time} ms 内找到 ${hits} 条结果"
    },
    valine: true,fancybox: true,
    copyright: '复制成功，转载请遵守 <i class="ic i-creative-commons"></i>BY-NC-SA 协议。',
    ignores : [
      function(uri) {
        return uri.includes('#');
      },
      function(uri) {
        return new RegExp(LOCAL.path+"$").test(uri);
      }
    ]
  };
</script>

<script src="https://cdn.polyfill.io/v2/polyfill.js"></script>

<script src="//cdn.jsdelivr.net/combine/npm/pace-js@1.0.2/pace.min.js,npm/pjax@0.2.8/pjax.min.js,npm/whatwg-fetch@3.4.0/dist/fetch.umd.min.js,npm/animejs@3.2.0/lib/anime.min.js,npm/algoliasearch@4/dist/algoliasearch-lite.umd.js,npm/instantsearch.js@4/dist/instantsearch.production.min.js,npm/lozad@1/dist/lozad.min.js,npm/quicklink@2/dist/quicklink.umd.js"></script>

<script src="/blog/js/app.js?v=0.2.5"></script>




</body>
</html>
